Subversion Repositories Games.Chess Giants

Rev

Rev 154 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. #include <stdarg.h>
  2. #include <errno.h>
  3. #include <ctype.h>
  4. #include "chess.h"
  5. #include "data.h"
  6. #if defined(UNIX)
  7. #  include <unistd.h>
  8. #  include <sys/types.h>
  9. #  include <signal.h>
  10. #  include <sys/wait.h>
  11. #  include <sys/times.h>
  12. #  include <sys/time.h>
  13. #else
  14. #  include <windows.h>
  15. #  include <winbase.h>
  16. #  include <wincon.h>
  17. #  include <io.h>
  18. #  include <time.h>
  19. #endif
  20.  
  21. /*
  22.  *******************************************************************************
  23.  *                                                                             *
  24.  *   AlignedMalloc() is used to allocate memory on a precise boundary,         *
  25.  *   primarily to optimize cache performance by forcing the start of the       *
  26.  *   memory region being allocated to match up so that a structure will lie    *
  27.  *   on a single cache line rather than being split across two, assuming the   *
  28.  *   structure is 64 bytes or less of course.                                  *
  29.  *                                                                             *
  30.  *******************************************************************************
  31.  */
  32. void AlignedMalloc(void **pointer, uint64_t alignment, size_t size) {
  33.   uint64_t temp;
  34.  
  35.   segments[nsegments][0] = malloc((size_t) (size + alignment - 1)); // Pierre-Marie Baty -- added type cast
  36.   segments[nsegments][1] = segments[nsegments][0];
  37.   temp = (uint64_t) segments[nsegments][0];
  38.   temp = (temp + alignment - 1) & ~(alignment - 1);
  39.   segments[nsegments][1] = (void *) temp;
  40.   *pointer = segments[nsegments][1];
  41.   nsegments++;
  42. }
  43.  
  44. /*
  45.  *******************************************************************************
  46.  *                                                                             *
  47.  *   atoiKMB() is used to read in an integer value that can have a "K" or "M"  *
  48.  *   appended to it to multiply by 1024 or 1024*1024.  It returns a 64 bit     *
  49.  *   value since memory sizes can exceed 4gb on modern hardware.               *
  50.  *                                                                             *
  51.  *******************************************************************************
  52.  */
  53. uint64_t atoiKMB(char *input) {
  54.   uint64_t size;
  55.  
  56.   size = atoi(input);
  57.   if (strchr(input, 'K') || strchr(input, 'k'))
  58.     size *= 1 << 10;
  59.   if (strchr(input, 'M') || strchr(input, 'm'))
  60.     size *= 1 << 20;
  61.   if (strchr(input, 'B') || strchr(input, 'b') || strchr(input, 'G') ||
  62.       strchr(input, 'g'))
  63.     size *= 1 << 30;
  64.   return size;
  65. }
  66.  
  67. /*
  68.  *******************************************************************************
  69.  *                                                                             *
  70.  *   AlignedRemalloc() is used to change the size of a memory block that has   *
  71.  *   previously been allocated using AlignedMalloc().                          *
  72.  *                                                                             *
  73.  *******************************************************************************
  74.  */
  75. void AlignedRemalloc(void **pointer, uint64_t alignment, size_t size) {
  76.   uint64_t temp;
  77.   int i;
  78.  
  79.   for (i = 0; i < nsegments; i++)
  80.     if (segments[i][1] == *pointer)
  81.       break;
  82.   if (i == nsegments) {
  83.     Print(4095, "ERROR  AlignedRemalloc() given an invalid pointer\n");
  84.     exit(1);
  85.   }
  86.   free(segments[i][0]);
  87.   segments[i][0] = malloc((size_t) (size + alignment - 1)); // Pierre-Marie Baty -- added type cast
  88.   temp = (uint64_t) segments[i][0];
  89.   temp = (temp + alignment - 1) & ~(alignment - 1);
  90.   segments[i][1] = (void *) temp;
  91.   *pointer = segments[i][1];
  92. }
  93.  
  94. /*
  95.  *******************************************************************************
  96.  *                                                                             *
  97.  *   BookClusterIn() is used to read a cluster in as characters, then stuff    *
  98.  *   the data into a normal array of structures that can be used within Crafty *
  99.  *   without any endian issues.                                                *
  100.  *                                                                             *
  101.  *******************************************************************************
  102.  */
  103. void BookClusterIn(FILE * file, int positions, BOOK_POSITION * buffer) {
  104.   int i;
  105.   char file_buffer[BOOK_CLUSTER_SIZE * sizeof(BOOK_POSITION)];
  106.  
  107.   i = fread(file_buffer, positions, sizeof(BOOK_POSITION), file);
  108.   if (i <= 0)
  109.     perror("BookClusterIn fread error: ");
  110.   for (i = 0; i < positions; i++) {
  111.     buffer[i].position =
  112.         BookIn64((unsigned char *) (file_buffer + i * sizeof(BOOK_POSITION)));
  113.     buffer[i].status_played =
  114.         BookIn32((unsigned char *) (file_buffer + i * sizeof(BOOK_POSITION) +
  115.             8));
  116.     buffer[i].learn =
  117.         BookIn32f((unsigned char *) (file_buffer + i * sizeof(BOOK_POSITION) +
  118.             12));
  119.   }
  120. }
  121.  
  122. /*
  123.  *******************************************************************************
  124.  *                                                                             *
  125.  *   BookClusterOut() is used to write a cluster out as characters, after      *
  126.  *   converting the normal array of structures into character data that is     *
  127.  *   Endian-independent.                                                       *
  128.  *                                                                             *
  129.  *******************************************************************************
  130.  */
  131. void BookClusterOut(FILE * file, int positions, BOOK_POSITION * buffer) {
  132.   int i;
  133.   char file_buffer[BOOK_CLUSTER_SIZE * sizeof(BOOK_POSITION)];
  134.  
  135.   for (i = 0; i < positions; i++) {
  136.     memcpy(file_buffer + i * sizeof(BOOK_POSITION),
  137.         BookOut64(buffer[i].position), 8);
  138.     memcpy(file_buffer + i * sizeof(BOOK_POSITION) + 8,
  139.         BookOut32(buffer[i].status_played), 4);
  140.     memcpy(file_buffer + i * sizeof(BOOK_POSITION) + 12,
  141.         BookOut32f(buffer[i].learn), 4);
  142.   }
  143.   fwrite(file_buffer, positions, sizeof(BOOK_POSITION), file);
  144. }
  145.  
  146. /*
  147.  *******************************************************************************
  148.  *                                                                             *
  149.  *   BookIn32f() is used to convert 4 bytes from the book file into a valid 32 *
  150.  *   bit binary value.  This eliminates endian worries that make the binary    *
  151.  *   book non-portable across many architectures.                              *
  152.  *                                                                             *
  153.  *******************************************************************************
  154.  */
  155. float BookIn32f(unsigned char *ch) {
  156.   union {
  157.     float fv;
  158.     int iv;
  159.   } temp;
  160.  
  161.   temp.iv = ch[3] << 24 | ch[2] << 16 | ch[1] << 8 | ch[0];
  162.   return temp.fv;
  163. }
  164.  
  165. /*
  166.  *******************************************************************************
  167.  *                                                                             *
  168.  *   BookIn32() is used to convert 4 bytes from the book file into a valid 32  *
  169.  *   bit binary value.  this eliminates endian worries that make the  binary   *
  170.  *   book non-portable across many architectures.                              *
  171.  *                                                                             *
  172.  *******************************************************************************
  173.  */
  174. int BookIn32(unsigned char *ch) {
  175.   return ch[3] << 24 | ch[2] << 16 | ch[1] << 8 | ch[0];
  176. }
  177.  
  178. /*
  179.  *******************************************************************************
  180.  *                                                                             *
  181.  *   BookIn64() is used to convert 8 bytes from the book file into a valid 64  *
  182.  *   bit binary value.  this eliminates endian worries that make the  binary   *
  183.  *   book non-portable across many architectures.                              *
  184.  *                                                                             *
  185.  *******************************************************************************
  186.  */
  187. uint64_t BookIn64(unsigned char *ch) {
  188.   return (uint64_t) ch[7] << 56 | (uint64_t) ch[6] << 48 | (uint64_t)
  189.       ch[5] << 40 | (uint64_t) ch[4] << 32 | (uint64_t) ch[3]
  190.       << 24 | (uint64_t) ch[2] << 16 | (uint64_t) ch[1] << 8 | (uint64_t)
  191.       ch[0];
  192. }
  193.  
  194. /*
  195.  *******************************************************************************
  196.  *                                                                             *
  197.  *   BookOut32() is used to convert 4 bytes from a valid 32 bit binary value   *
  198.  *   to a book value.  this eliminates endian worries that make the  binary    *
  199.  *   book non-portable across many architectures.                              *
  200.  *                                                                             *
  201.  *******************************************************************************
  202.  */
  203. unsigned char *BookOut32(int val) {
  204.   convert_buff[3] = val >> 24 & 0xff;
  205.   convert_buff[2] = val >> 16 & 0xff;
  206.   convert_buff[1] = val >> 8 & 0xff;
  207.   convert_buff[0] = val & 0xff;
  208.   return convert_buff;
  209. }
  210.  
  211. /*
  212.  *******************************************************************************
  213.  *                                                                             *
  214.  *   BookOut32f() is used to convert 4 bytes from a valid 32 bit binary value  *
  215.  *   to a book value.  this eliminates endian worries that make the  binary    *
  216.  *   book non-portable across many architectures.                              *
  217.  *                                                                             *
  218.  *******************************************************************************
  219.  */
  220. unsigned char *BookOut32f(float val) {
  221.   union {
  222.     float fv;
  223.     int iv;
  224.   } temp;
  225.  
  226.   temp.fv = val;
  227.   convert_buff[3] = temp.iv >> 24 & 0xff;
  228.   convert_buff[2] = temp.iv >> 16 & 0xff;
  229.   convert_buff[1] = temp.iv >> 8 & 0xff;
  230.   convert_buff[0] = temp.iv & 0xff;
  231.   return convert_buff;
  232. }
  233.  
  234. /*
  235.  *******************************************************************************
  236.  *                                                                             *
  237.  *   BookOut64() is used to convert 8 bytes from a valid 64 bit binary value   *
  238.  *   to a book value.  this eliminates endian worries that make the  binary    *
  239.  *   book non-portable across many architectures.                              *
  240.  *                                                                             *
  241.  *******************************************************************************
  242.  */
  243. unsigned char *BookOut64(uint64_t val) {
  244.   convert_buff[7] = val >> 56 & 0xff;
  245.   convert_buff[6] = val >> 48 & 0xff;
  246.   convert_buff[5] = val >> 40 & 0xff;
  247.   convert_buff[4] = val >> 32 & 0xff;
  248.   convert_buff[3] = val >> 24 & 0xff;
  249.   convert_buff[2] = val >> 16 & 0xff;
  250.   convert_buff[1] = val >> 8 & 0xff;
  251.   convert_buff[0] = val & 0xff;
  252.   return convert_buff;
  253. }
  254.  
  255. /*
  256.  *******************************************************************************
  257.  *                                                                             *
  258.  *   the following functions are used to determine if keyboard input is        *
  259.  *   present.  there are several ways this is done depending on which          *
  260.  *   operating system is used.  The primary function name is CheckInput() but  *
  261.  *   for simplicity there are several O/S-specific versions.                   *
  262.  *                                                                             *
  263.  *******************************************************************************
  264.  */
  265. #if !defined(UNIX)
  266. #  include <windows.h>
  267. #  include <conio.h>
  268. /* Windows NT using PeekNamedPipe() function */
  269. int CheckInput(void) {
  270.   int i;
  271.   static int init = 0, pipe;
  272.   static HANDLE inh;
  273.   DWORD dw;
  274.  
  275.   if (!xboard && !_isatty(_fileno(stdin))) // Pierre-Marie Baty -- ISO C++ name conformance fixes
  276.     return 0;
  277.   if (batch_mode)
  278.     return 0;
  279.   if (strchr(cmd_buffer, '\n'))
  280.     return 1;
  281.   if (xboard) {
  282. #  if defined(FILE_CNT)
  283.     if (stdin->_cnt > 0)
  284.       return stdin->_cnt;
  285. #  endif
  286.     if (!init) {
  287.       init = 1;
  288.       inh = GetStdHandle(STD_INPUT_HANDLE);
  289.       pipe = !GetConsoleMode(inh, &dw);
  290.       if (!pipe) {
  291.         SetConsoleMode(inh, dw & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT));
  292.         FlushConsoleInputBuffer(inh);
  293.       }
  294.     }
  295.     if (pipe) {
  296.       if (!PeekNamedPipe(inh, NULL, 0, NULL, &dw, NULL)) {
  297.         return 1;
  298.       }
  299.       return dw;
  300.     } else {
  301.       GetNumberOfConsoleInputEvents(inh, &dw);
  302.       return dw <= 1 ? 0 : dw;
  303.     }
  304.   } else {
  305.     i = _kbhit();
  306.   }
  307.   return i;
  308. }
  309. #endif
  310. #if defined(UNIX)
  311. /* Simple UNIX approach using select with a zero timeout value */
  312. int CheckInput(void) {
  313.   fd_set readfds;
  314.   struct timeval tv;
  315.   int data;
  316.  
  317.   if (!xboard && !isatty(fileno(stdin)))
  318.     return 0;
  319.   if (batch_mode)
  320.     return 0;
  321.   if (strchr(cmd_buffer, '\n'))
  322.     return 1;
  323.   FD_ZERO(&readfds);
  324.   FD_SET(fileno(stdin), &readfds);
  325.   tv.tv_sec = 0;
  326.   tv.tv_usec = 0;
  327.   select(16, &readfds, 0, 0, &tv);
  328.   data = FD_ISSET(fileno(stdin), &readfds);
  329.   return data;
  330. }
  331. #endif
  332.  
  333. /*
  334.  *******************************************************************************
  335.  *                                                                             *
  336.  *   ClearHashTableScores() is used to clear hash table scores without         *
  337.  *   clearing the best move, so that move ordering information is preserved.   *
  338.  *   We clear the scorew as we approach a 50 move rule so that hash scores     *
  339.  *   won't give us false scores since the hash signature does not include any  *
  340.  *   search path information in it.                                            *
  341.  *                                                                             *
  342.  *******************************************************************************
  343.  */
  344. void ClearHashTableScores(void) {
  345.   unsigned int i; // Pierre-Marie Baty -- fixed type
  346.  
  347.   if (hash_table)
  348.     for (i = 0; i < hash_table_size; i++) {
  349.       (hash_table + i)->word2 ^= (hash_table + i)->word1;
  350.       (hash_table + i)->word1 =
  351.           ((hash_table + i)->word1 & mask_clear_entry) | (uint64_t) 65536;
  352.       (hash_table + i)->word2 ^= (hash_table + i)->word1;
  353.     }
  354. }
  355.  
  356. /* last modified 02/28/14 */
  357. /*
  358.  *******************************************************************************
  359.  *                                                                             *
  360.  *   ComputeDifficulty() is used to compute the difficulty rating for the      *
  361.  *   current position, which really is based on nothing more than how many     *
  362.  *   times we changed our mind in an iteration.  No changes caused the         *
  363.  *   difficulty to drop (easier, use less time), while more changes ramps the  *
  364.  *   difficulty up (harder, use more time).  It is called at the end of an     *
  365.  *   iteration as well as when displaying fail-high/fail-low moves, in an      *
  366.  *   effort to give the operator a heads-up on how long we are going to be     *
  367.  *   stuck in an active search.                                                *
  368.  *                                                                             *
  369.  *******************************************************************************
  370.  */
  371. int ComputeDifficulty(int difficulty, int direction) {
  372.   int searched = 0, i;
  373.  
  374. /*
  375.  ************************************************************
  376.  *                                                          *
  377.  *  Step 1.  Handle fail-high-fail low conditions, which    *
  378.  *  occur in the middle of an iteration.  The actions taken *
  379.  *  are as follows:                                         *
  380.  *                                                          *
  381.  *  (1) Determine how many moves we have searched first, as *
  382.  *  this is important.  If we have not searched anything    *
  383.  *  (which means we failed high on the first move at the    *
  384.  *  root, at the beginning of a new iteration), a fail low  *
  385.  *  will immediately set difficult back to 100% (if it is   *
  386.  *  currently below 100%).  A fail high on the first move   *
  387.  *  will not change difficulty at all.  Successive fail     *
  388.  *  highs or fail lows will not change difficulty, we will  *
  389.  *  not even get into this code on the repeats.             *
  390.  *                                                          *
  391.  *  (2) If we are beyond the first move, then this must be  *
  392.  *  a fail high condition.  Since we are changing our mind, *
  393.  *  we need to increase the difficulty level to expend more *
  394.  *  time on this iteration.  If difficulty is currently     *
  395.  *  less than 100%, we set it to 120%.  If it is currently  *
  396.  *  at 100% or more, we simply add 20% to the value and     *
  397.  *  continue searching, but with a longer time constraint.  *
  398.  *  Each time we fail high, we are changing our mind, and   *
  399.  *  we will increase difficulty by another 20%.             *
  400.  *                                                          *
  401.  *  (3) Direction = 0 means we are at the end of an the     *
  402.  *  iteration.  Here we simply note if we changed our mind  *
  403.  *  during this iteration.  If not, we reduce difficulty    *
  404.  *  to 90% of its previous value.                           *
  405.  *                                                          *
  406.  *  After any of these changes, we enforce a lower bound of *
  407.  *  60% and an upperbound of 200% before we return.         *
  408.  *                                                          *
  409.  *  Note:  direction = +1 means we failed high on the move, *
  410.  *  direction = -1 means we failed low on the move, and     *
  411.  *  direction = 0 means we have completed the iteration and *
  412.  *  all moves were searched successfully.                   *
  413.  *                                                          *
  414.  ************************************************************
  415.  */
  416.   if (direction) {
  417.     for (i = 0; i < n_root_moves; i++)
  418.       if (root_moves[i].status & 8)
  419.         searched++;
  420.     if (searched == 0) {
  421.       if (direction > 0)
  422.         return difficulty;
  423.       if (direction < 0)
  424.         difficulty = Max(100, difficulty);
  425.     } else {
  426.       if (difficulty < 100)
  427.         difficulty = 120;
  428.       else
  429.         difficulty = difficulty + 20;
  430.     }
  431.   }
  432. /*
  433.  ************************************************************
  434.  *                                                          *
  435.  *  Step 2.  We are at the end of an iteration.  If we did  *
  436.  *  not change our mind and stuck with one move, we reduce  *
  437.  *  difficulty by 10% since the move looks to be a little   *
  438.  *  "easier" when we don't change our mind.                 *
  439.  *                                                          *
  440.  ************************************************************
  441.  */
  442.   else {
  443.     searched = 0;
  444.     for (i = 0; i < n_root_moves; i++)
  445.       if (root_moves[i].bm_age == 3)
  446.         searched++;
  447.     if (searched <= 1)
  448.       difficulty = 90 * difficulty / 100;
  449.   }
  450. /*
  451.  ************************************************************
  452.  *                                                          *
  453.  *  Step 4.  Apply limits.  We don't let difficulty go      *
  454.  *  above 200% (take 2x the target time) nor do we let it   *
  455.  *  drop below 60 (take .6x target time) to avoid moving    *
  456.  *  too quickly and missing something tactically where the  *
  457.  *  move initially looks obvious but really is not.         *
  458.  *                                                          *
  459.  ************************************************************
  460.  */
  461.   difficulty = Max(60, Min(difficulty, 200));
  462.   return difficulty;
  463. }
  464.  
  465. /*
  466.  *******************************************************************************
  467.  *                                                                             *
  468.  *   CraftyExit() is used to terminate the program.  the main functionality    *
  469.  *   is to make sure the "quit" flag is set so that any spinning threads will  *
  470.  *   also exit() rather than spinning forever which can cause GUIs to hang     *
  471.  *   since all processes have not terminated.                                  *
  472.  *                                                                             *
  473.  *******************************************************************************
  474.  */
  475. void CraftyExit(int exit_type) {
  476.   int proc;
  477.  
  478.   for (proc = 1; proc < CPUS; proc++)
  479.     thread[proc].terminate = 1;
  480.   while (smp_threads);
  481.   exit(exit_type);
  482. }
  483.  
  484. /*
  485.  *******************************************************************************
  486.  *                                                                             *
  487.  *   DisplayArray() prints array data either 8 or 16 values per line, and also *
  488.  *   reverses the output for arrays that overlay the chess board so that the   *
  489.  *   'white side" is at the bottom rather than the top.  this is mainly used   *
  490.  *   from inside Option() to display the many evaluation terms.                *
  491.  *                                                                             *
  492.  *******************************************************************************
  493.  */
  494. void DisplayArray(int *array, int size) {
  495.   int i, j, len = 16;
  496.  
  497.   if (Abs(size) % 10 == 0)
  498.     len = 10;
  499.   else if (Abs(size) % 8 == 0)
  500.     len = 8;
  501.   if (size > 0 && size % 16 == 0 && len == 8)
  502.     len = 16;
  503.   if (size > 0) {
  504.     printf("    ");
  505.     for (i = 0; i < size; i++) {
  506.       printf("%3d ", array[i]);
  507.       if ((i + 1) % len == 0) {
  508.         printf("\n");
  509.         if (i < size - 1)
  510.           printf("    ");
  511.       }
  512.     }
  513.     if (i % len != 0)
  514.       printf("\n");
  515.   }
  516.   if (size < 0) {
  517.     for (i = 0; i < 8; i++) {
  518.       printf("    ");
  519.       for (j = 0; j < 8; j++) {
  520.         printf("%3d ", array[(7 - i) * 8 + j]);
  521.       }
  522.       printf(" | %d\n", 8 - i);
  523.     }
  524.     printf("    ---------------------------------\n");
  525.     printf("      a   b   c   d   e   f   g   h\n");
  526.   }
  527. }
  528.  
  529. /*
  530.  *******************************************************************************
  531.  *                                                                             *
  532.  *   DisplayArray() prints array data either 8 or 16 values per line, and also *
  533.  *   reverses the output for arrays that overlay the chess board so that the   *
  534.  *   'white side" is at the bottom rather than the top.  this is mainly used   *
  535.  *   from inside Option() to display the many evaluation terms.                *
  536.  *                                                                             *
  537.  *******************************************************************************
  538.  */
  539. void DisplayArrayX2(int *array, int *array2, int size) {
  540.   int i, j;
  541.  
  542.   if (size == 256) {
  543.     printf("    ----------- Middlegame -----------   ");
  544.     printf("    ------------- Endgame -----------\n");
  545.     for (i = 0; i < 8; i++) {
  546.       printf("    ");
  547.       for (j = 0; j < 8; j++)
  548.         printf("%3d ", array[(7 - i) * 8 + j]);
  549.       printf("  |  %d  |", 8 - i);
  550.       printf("  ");
  551.       for (j = 0; j < 8; j++)
  552.         printf("%3d ", array2[(7 - i) * 8 + j]);
  553.       printf("\n");
  554.     }
  555.     printf
  556.         ("    ----------------------------------       ---------------------------------\n");
  557.     printf("      a   b   c   d   e   f   g   h        ");
  558.     printf("      a   b   c   d   e   f   g   h\n");
  559.   } else if (size == 32) {
  560.     printf("    ----------- Middlegame -----------   ");
  561.     printf("    ------------- Endgame -----------\n");
  562.     printf("    ");
  563.     for (i = 0; i < 8; i++)
  564.       printf("%3d ", array[i]);
  565.     printf("  |     |");
  566.     printf("  ");
  567.     for (i = 0; i < 8; i++)
  568.       printf("%3d ", array2[i]);
  569.     printf("\n");
  570.   } else if (size <= 20) {
  571.     size = size / 2;
  572.     printf("    ");
  573.     for (i = 0; i < size; i++)
  574.       printf("%3d ", array[i]);
  575.     printf("  |<mg    eg>|");
  576.     printf("  ");
  577.     for (i = 0; i < size; i++)
  578.       printf("%3d ", array2[i]);
  579.     printf("\n");
  580.   } else if (size > 128) {
  581.     printf("    ----------- Middlegame -----------   ");
  582.     printf("    ------------- Endgame -----------\n");
  583.     for (i = 0; i < size / 32; i++) {
  584.       printf("    ");
  585.       for (j = 0; j < 8; j++)
  586.         printf("%3d ", array[(7 - i) * 8 + j]);
  587.       printf("  |  %d  |", 8 - i);
  588.       printf("  ");
  589.       for (j = 0; j < 8; j++)
  590.         printf("%3d ", array2[(7 - i) * 8 + j]);
  591.       printf("\n");
  592.     }
  593.   } else
  594.     Print(4095, "ERROR, invalid size = -%d in packet\n", size);
  595. }
  596.  
  597. /*
  598.  *******************************************************************************
  599.  *                                                                             *
  600.  *   DisplayBitBoard() is a debugging function used to display bitboards in a  *
  601.  *   more visual way.  they are displayed as an 8x8 matrix oriented as the     *
  602.  *   normal chess board is, with a1 at the lower left corner.                  *
  603.  *                                                                             *
  604.  *******************************************************************************
  605.  */
  606. void DisplayBitBoard(uint64_t board) {
  607.   int i, j, x;
  608.  
  609.   for (i = 56; i >= 0; i -= 8) {
  610.     x = (board >> i) & 255;
  611.     for (j = 1; j < 256; j = j << 1)
  612.       if (x & j)
  613.         Print(4095, "X ");
  614.       else
  615.         Print(4095, "- ");
  616.     Print(4095, "\n");
  617.   }
  618. }
  619.  
  620. /*
  621.  *******************************************************************************
  622.  *                                                                             *
  623.  *   Display2BitBoards() is a debugging function used to display bitboards in  *
  624.  *   a more visual way.  they are displayed as an 8x8 matrix oriented as the   *
  625.  *   normal chess board is, with a1 at the lower left corner.  this function   *
  626.  *   displays 2 boards side by side for comparison.                            *
  627.  *                                                                             *
  628.  *******************************************************************************
  629.  */
  630. void Display2BitBoards(uint64_t board1, uint64_t board2) {
  631.   int i, j, x, y;
  632.  
  633.   for (i = 56; i >= 0; i -= 8) {
  634.     x = (board1 >> i) & 255;
  635.     for (j = 1; j < 256; j = j << 1)
  636.       if (x & j)
  637.         printf("X ");
  638.       else
  639.         printf("- ");
  640.     printf("    ");
  641.     y = (board2 >> i) & 255;
  642.     for (j = 1; j < 256; j = j << 1)
  643.       if (y & j)
  644.         printf("X ");
  645.       else
  646.         printf("- ");
  647.     printf("\n");
  648.   }
  649. }
  650.  
  651. /*
  652.  *******************************************************************************
  653.  *                                                                             *
  654.  *   DisplayChessBoard() is used to display the board since it is kept in      *
  655.  *   both the bit-board and array formats, here we use the array format which  *
  656.  *   is nearly ready for display as is.                                        *
  657.  *                                                                             *
  658.  *******************************************************************************
  659.  */
  660. void DisplayChessBoard(FILE * display_file, POSITION pos) {
  661.   int display_board[64], i, j;
  662.   static const char display_string[16][4] =
  663.       { "<K>", "<Q>", "<R>", "<B>", "<N>", "<P>", "   ",
  664.     "-P-", "-N-", "-B-", "-R-", "-Q-", "-K-", " . "
  665.   };
  666.  
  667. /*
  668.  ************************************************************
  669.  *                                                          *
  670.  *  First, convert square values to indices to the proper   *
  671.  *  text string.                                            *
  672.  *                                                          *
  673.  ************************************************************
  674.  */
  675.   for (i = 0; i < 64; i++) {
  676.     display_board[i] = pos.board[i] + 6;
  677.     if (pos.board[i] == 0) {
  678.       if (((i / 8) & 1) == ((i % 8) & 1))
  679.         display_board[i] = 13;
  680.     }
  681.   }
  682. /*
  683.  ************************************************************
  684.  *                                                          *
  685.  *  Now that that's done, simply display using 8 squares    *
  686.  *  per line.                                               *
  687.  *                                                          *
  688.  ************************************************************
  689.  */
  690.   fprintf(display_file, "\n       +---+---+---+---+---+---+---+---+\n");
  691.   for (i = 7; i >= 0; i--) {
  692.     fprintf(display_file, "   %2d  ", i + 1);
  693.     for (j = 0; j < 8; j++)
  694.       fprintf(display_file, "|%s", display_string[display_board[i * 8 + j]]);
  695.     fprintf(display_file, "|\n");
  696.     fprintf(display_file, "       +---+---+---+---+---+---+---+---+\n");
  697.   }
  698.   fprintf(display_file, "         a   b   c   d   e   f   g   h\n\n");
  699. }
  700.  
  701. /*
  702.  *******************************************************************************
  703.  *                                                                             *
  704.  *   DisplayChessMove() is a debugging function that displays a chess move in  *
  705.  *   a very simple (non-algebraic) form.                                       *
  706.  *                                                                             *
  707.  *******************************************************************************
  708.  */
  709. void DisplayChessMove(char *title, int move) {
  710.   Print(4095, "%s  piece=%d, from=%d, to=%d, captured=%d, promote=%d\n",
  711.       title, Piece(move), From(move), To(move), Captured(move),
  712.       Promote(move));
  713. }
  714.  
  715. /*
  716.  *******************************************************************************
  717.  *                                                                             *
  718.  *   DisplayEvaluation() is used to convert the evaluation to a string that    *
  719.  *   can be displayed.  The length is fixed so that screen formatting will     *
  720.  *   look nice and aligned.                                                    *
  721.  *                                                                             *
  722.  *******************************************************************************
  723.  */
  724. char *DisplayEvaluation(int value, int wtm) {
  725.   int tvalue;
  726.   static char out[20];
  727.  
  728.   tvalue = (wtm) ? value : -value;
  729.   if (!MateScore(value) && !EGTBScore(value))
  730.     sprintf(out, "%7.2f", ((float) tvalue) / 100.0);
  731.   else if (Abs(value) > MATE) {
  732.     if (tvalue < 0)
  733.       sprintf(out, " -infnty");
  734.     else
  735.       sprintf(out, " +infnty");
  736.   } else {
  737.     if (EGTBScore(value)) {
  738.       if (wtm) {
  739.         if (value == TBWIN)
  740.           sprintf(out, "   Won ");
  741.         else if (value == -TBWIN)
  742.           sprintf(out, "  Lost ");
  743.       } else {
  744.         if (value == TBWIN)
  745.           sprintf(out, "  -Won ");
  746.         else if (value == -TBWIN)
  747.           sprintf(out, " -Lost ");
  748.       }
  749.     }
  750.     if (MateScore(value)) {
  751.       if (value == MATE - 2 && wtm)
  752.         sprintf(out, "   Mate");
  753.       else if (value == MATE - 2 && !wtm)
  754.         sprintf(out, "  -Mate");
  755.       else if (value == -(MATE - 1) && wtm)
  756.         sprintf(out, "  -Mate");
  757.       else if (value == -(MATE - 1) && !wtm)
  758.         sprintf(out, "   Mate");
  759.       else if (value > 0 && wtm)
  760.         sprintf(out, "  Mat%.2d", (MATE - value) / 2);
  761.       else if (value > 0 && !wtm)
  762.         sprintf(out, " -Mat%.2d", (MATE - value) / 2);
  763.       else if (wtm)
  764.         sprintf(out, " -Mat%.2d", (MATE - Abs(value)) / 2);
  765.       else
  766.         sprintf(out, "  Mat%.2d", (MATE - Abs(value)) / 2);
  767.     }
  768.   }
  769.   return out;
  770. }
  771.  
  772. /*
  773.  *******************************************************************************
  774.  *                                                                             *
  775.  *   DisplayEvaluationKibitz() is used to convert the evaluation to a string   *
  776.  *   that can be displayed.  The length is variable so that ICC kibitzes and   *
  777.  *   whispers will look nicer.                                                 *
  778.  *                                                                             *
  779.  *******************************************************************************
  780.  */
  781. char *DisplayEvaluationKibitz(int value, int wtm) {
  782.   int tvalue;
  783.   static char out[10];
  784.  
  785.   tvalue = (wtm) ? value : -value;
  786.   if (!MateScore(value))
  787.     sprintf(out, "%+.2f", ((float) tvalue) / 100.0);
  788.   else if (Abs(value) > MATE) {
  789.     if (tvalue < 0)
  790.       sprintf(out, "-infnty");
  791.     else
  792.       sprintf(out, "+infnty");
  793.   } else if (value == MATE - 2 && wtm)
  794.     sprintf(out, "Mate");
  795.   else if (value == MATE - 2 && !wtm)
  796.     sprintf(out, "-Mate");
  797.   else if (value == -(MATE - 1) && wtm)
  798.     sprintf(out, "-Mate");
  799.   else if (value == -(MATE - 1) && !wtm)
  800.     sprintf(out, "Mate");
  801.   else if (value > 0 && wtm)
  802.     sprintf(out, "Mat%.2d", (MATE - value) / 2);
  803.   else if (value > 0 && !wtm)
  804.     sprintf(out, "-Mat%.2d", (MATE - value) / 2);
  805.   else if (wtm)
  806.     sprintf(out, "-Mat%.2d", (MATE - Abs(value)) / 2);
  807.   else
  808.     sprintf(out, "Mat%.2d", (MATE - Abs(value)) / 2);
  809.   return out;
  810. }
  811.  
  812. /*
  813.  *******************************************************************************
  814.  *                                                                             *
  815.  *   DisplayPath() is used to display a PV during the root move search.        *
  816.  *                                                                             *
  817.  *******************************************************************************
  818.  */
  819. char *DisplayPath(TREE * RESTRICT tree, int wtm, PATH * pv) {
  820.   static char buffer[4096];
  821.   int i, t_move_number;
  822.  
  823. /*
  824.  ************************************************************
  825.  *                                                          *
  826.  *  Initialize.                                             *
  827.  *                                                          *
  828.  ************************************************************
  829.  */
  830.   t_move_number = move_number;
  831.   sprintf(buffer, " %d.", move_number);
  832.   if (!wtm)
  833.     sprintf(buffer + strlen(buffer), " ...");
  834.   for (i = 1; i < (int) pv->pathl; i++) {
  835.     if (i > 1 && wtm)
  836.       sprintf(buffer + strlen(buffer), " %d.", t_move_number);
  837.     sprintf(buffer + strlen(buffer), " %s", OutputMove(tree, i, wtm,
  838.             pv->path[i]));
  839.     MakeMove(tree, i, wtm, pv->path[i]);
  840.     wtm = Flip(wtm);
  841.     if (wtm)
  842.       t_move_number++;
  843.   }
  844.   if (pv->pathh == 1)
  845.     sprintf(buffer + strlen(buffer), " <HT>");
  846.   else if (pv->pathh == 2)
  847.     sprintf(buffer + strlen(buffer), " <3-fold>");
  848.   else if (pv->pathh == 3)
  849.     sprintf(buffer + strlen(buffer), " <50-move>");
  850.   else if (pv->pathh == 4)
  851.     sprintf(buffer + strlen(buffer), " <EGTB>");
  852.   if (strlen(buffer) < 30)
  853.     for (i = 0; i < 30 - (int) strlen(buffer); i++) // Pierre-Marie Baty -- added type cast
  854.       strcat(buffer, " ");
  855.   strcpy(kibitz_text, buffer);
  856.   for (i = pv->pathl - 1; i > 0; i--) {
  857.     wtm = Flip(wtm);
  858.     UnmakeMove(tree, i, wtm, pv->path[i]);
  859.   }
  860.   return buffer;
  861. }
  862.  
  863. /*
  864.  *******************************************************************************
  865.  *                                                                             *
  866.  *   DisplayFail() is used to display a move that fails high or low during     *
  867.  *   the search.  Normally disabled.                                           *
  868.  *                                                                             *
  869.  *******************************************************************************
  870.  */
  871. void DisplayFail(TREE * RESTRICT tree, int type, int level, int wtm, int time,
  872.     int move, int value, int force) {
  873.   char buffer[4096], *fh_indicator;
  874.  
  875. /*
  876.  ************************************************************
  877.  *                                                          *
  878.  *  If we have not used "noise_level" units of time, we     *
  879.  *  return immediately.  Otherwise we add the fail high/low *
  880.  *  indicator (++/--) and then display the times.           *
  881.  *                                                          *
  882.  ************************************************************
  883.  */
  884.   if (time < (int) noise_level) // Pierre-Marie Baty -- added type cast
  885.     return;
  886.   if (type == 1)
  887.     fh_indicator = (wtm) ? "++" : "--";
  888.   else
  889.     fh_indicator = (wtm) ? "--" : "++";
  890.   Print(4, "         %2i   %s     %2s   ", iteration,
  891.       Display2Times(end_time - start_time), fh_indicator);
  892. /*
  893.  ************************************************************
  894.  *                                                          *
  895.  *  If we are pondering, we need to add the (ponder-move)   *
  896.  *  to the front of the buffer, correcting the move number  *
  897.  *  if necessary.  Then fill in the move number and the     *
  898.  *  fail high/low bound.                                    *
  899.  *                                                          *
  900.  ************************************************************
  901.  */
  902.   if (!pondering) {
  903.     sprintf(buffer, "%d.", move_number);
  904.     if (!wtm)
  905.       sprintf(buffer + strlen(buffer), " ...");
  906.   } else {
  907.     if (wtm)
  908.       sprintf(buffer, "%d. ... (%s) %d.", move_number - 1, ponder_text,
  909.           move_number);
  910.     else
  911.       sprintf(buffer, "%d. (%s)", move_number, ponder_text);
  912.   }
  913.   sprintf(buffer + strlen(buffer), " %s%c", OutputMove(tree, 1, wtm, move),
  914.       (type == 1) ? '!' : '?');
  915.   strcpy(kibitz_text, buffer);
  916.   if (time >= (int) noise_level || force) { // Pierre-Marie Baty -- added type cast
  917.     noise_block = 0;
  918.     Lock(lock_io);
  919.     Print(4, "%s", buffer);
  920.     Unlock(lock_io);
  921.     if (type == 1)
  922.       Print(4, " (%c%s)                   \n", (wtm) ? '>' : '<',
  923.           DisplayEvaluationKibitz(value, wtm));
  924.     else
  925.       Print(4, " (%c%s)                   \n", (wtm) ? '<' : '>',
  926.           DisplayEvaluationKibitz(value, wtm));
  927.   }
  928. }
  929.  
  930. /*
  931.  *******************************************************************************
  932.  *                                                                             *
  933.  *   DisplayPV() is used to display a PV during the search.                    *
  934.  *                                                                             *
  935.  *******************************************************************************
  936.  */
  937. void DisplayPV(TREE * RESTRICT tree, int level, int wtm, int time, PATH * pv,
  938.     int force) {
  939.   char buffer[4096], *buffp, *bufftemp;
  940.   char blanks[40] = { "                                        " };
  941.   int i, len, t_move_number, nskip = 0, twtm = wtm, pv_depth = pv->pathd;;
  942.   unsigned int idle_time;
  943.  
  944. /*
  945.  ************************************************************
  946.  *                                                          *
  947.  *  Initialize.                                             *
  948.  *                                                          *
  949.  ************************************************************
  950.  */
  951.   for (i = 0; i < n_root_moves; i++)
  952.     if (root_moves[i].status & 4)
  953.       nskip++;
  954.   for (i = 0; i < 4096; i++)
  955.     buffer[i] = ' ';
  956.   t_move_number = move_number;
  957.   if (!pondering || analyze_mode) {
  958.     sprintf(buffer, "%d.", move_number);
  959.     if (!wtm)
  960.       sprintf(buffer + strlen(buffer), " ...");
  961.   } else {
  962.     if (wtm)
  963.       sprintf(buffer, "%d. ... (%s) %d.", move_number - 1, ponder_text,
  964.           move_number);
  965.     else
  966.       sprintf(buffer, "%d. (%s)", move_number, ponder_text);
  967.   }
  968.   for (i = 1; i < (int) pv->pathl; i++) {
  969.     if (i > 1 && wtm)
  970.       sprintf(buffer + strlen(buffer), " %d.", t_move_number);
  971.     sprintf(buffer + strlen(buffer), " %s", OutputMove(tree, i, wtm,
  972.             pv->path[i]));
  973.     MakeMove(tree, i, wtm, pv->path[i]);
  974.     wtm = Flip(wtm);
  975.     if (wtm)
  976.       t_move_number++;
  977.   }
  978.   if (pv->pathh == 1)
  979.     sprintf(buffer + strlen(buffer), " <HT>");
  980.   else if (pv->pathh == 2)
  981.     sprintf(buffer + strlen(buffer), " <3-fold>");
  982.   else if (pv->pathh == 3)
  983.     sprintf(buffer + strlen(buffer), " <50-move>");
  984.   else if (pv->pathh == 4)
  985.     sprintf(buffer + strlen(buffer), " <EGTB>");
  986.   if (nskip > 1 && smp_max_threads > 1)
  987.     sprintf(buffer + strlen(buffer), " (s=%d)", nskip);
  988.   if (strlen(buffer) < 30) {
  989.     len = 30 - strlen(buffer);
  990.     for (i = 0; i < len; i++)
  991.       strcat(buffer, " ");
  992.   }
  993.   strcpy(kibitz_text, buffer);
  994.   if (time >= (int) noise_level || force) { // Pierre-Marie Baty -- added type cast
  995.     noise_block = 0;
  996.     Lock(lock_io);
  997.     Print(2, "         ");
  998.     if (level == 6)
  999.       Print(2, "%2i   %s%s   ", pv_depth, Display2Times(time),
  1000.           DisplayEvaluation(pv->pathv, twtm));
  1001.     else
  1002.       Print(2, "%2i-> %s%s   ", pv_depth, Display2Times(time)
  1003.           , DisplayEvaluation(pv->pathv, twtm));
  1004.     buffp = buffer;
  1005.     do {
  1006.       if ((int) strlen(buffp) > line_length - 38) {
  1007.         bufftemp = buffp + line_length - 38;
  1008.         while (*bufftemp != ' ')
  1009.           bufftemp--;
  1010.         if (*(bufftemp - 1) == '.')
  1011.           while (*(--bufftemp) != ' ');
  1012.       } else
  1013.         bufftemp = 0;
  1014.       if (bufftemp)
  1015.         *bufftemp = 0;
  1016.       Print(2, "%s\n", buffp);
  1017.       buffp = bufftemp + 1;
  1018.       if (bufftemp)
  1019.         if (!strncmp(buffp, blanks, strlen(buffp)))
  1020.           bufftemp = 0;
  1021.       if (bufftemp)
  1022.         Print(2, "                                     ");
  1023.     } while (bufftemp);
  1024.     idle_time = 0;
  1025.     for (i = 0; i < smp_max_threads; i++)
  1026.       idle_time += thread[i].idle;
  1027.     busy_percent =
  1028.         100 - Min(100,
  1029.         100 * idle_time / (smp_max_threads * (end_time - start_time) + 1));
  1030.     Kibitz(level, twtm, pv_depth, end_time - start_time, pv->pathv,
  1031.         tree->nodes_searched, busy_percent, (int) tree->egtb_hits, kibitz_text); // Pierre-Marie Baty -- added type cast
  1032.     Unlock(lock_io);
  1033.   }
  1034.   for (i = pv->pathl - 1; i > 0; i--) {
  1035.     wtm = Flip(wtm);
  1036.     UnmakeMove(tree, i, wtm, pv->path[i]);
  1037.   }
  1038. }
  1039.  
  1040. /*
  1041.  *******************************************************************************
  1042.  *                                                                             *
  1043.  *   DisplayHHMMSS is used to convert integer time values in 1/100th second    *
  1044.  *   units into a traditional output format for time, hh:mm:ss rather than     *
  1045.  *   just nnn.n seconds.                                                       *
  1046.  *                                                                             *
  1047.  *******************************************************************************
  1048.  */
  1049. char *DisplayHHMMSS(unsigned int time) {
  1050.   static char out[32];
  1051.  
  1052.   time = time / 100;
  1053.   sprintf(out, "%3u:%02u:%02u", time / 3600, (time % 3600) / 60, time % 60);
  1054.   return out;
  1055. }
  1056.  
  1057. /*
  1058.  *******************************************************************************
  1059.  *                                                                             *
  1060.  *   DisplayHHMM is used to convert integer time values in 1/100th second      *
  1061.  *   units into a traditional output format for time, mm:ss rather than just   *
  1062.  *   nnn.n seconds.                                                            *
  1063.  *                                                                             *
  1064.  *******************************************************************************
  1065.  */
  1066. char *DisplayHHMM(unsigned int time) {
  1067.   static char out[10];
  1068.  
  1069.   time = time / 6000;
  1070.   sprintf(out, "%3u:%02u", time / 60, time % 60);
  1071.   return out;
  1072. }
  1073.  
  1074. /*
  1075.  *******************************************************************************
  1076.  *                                                                             *
  1077.  *   DisplayKMB() takes an integer value that represents nodes per second, or  *
  1078.  *   just total nodes, and converts it into a more compact form, so that       *
  1079.  *   instead of nps=57200931, we get nps=57.2M.  We use units of "K", "M",     *
  1080.  *   "B" and "T".  If type==0, K=1000, etc.  If type=1, K=1024, etc.           *
  1081.  *                                                                             *
  1082.  *******************************************************************************
  1083.  */
  1084. char *DisplayKMB(uint64_t val, int type) {
  1085.   static char out[10];
  1086.  
  1087.   if (type == 0) {
  1088.     if (val < 1000)
  1089.       sprintf(out, "%" PRIu64, val);
  1090.     else if (val < 1000000)
  1091.       sprintf(out, "%.1fK", (double) val / 1000);
  1092.     else if (val < 1000000000)
  1093.       sprintf(out, "%.1fM", (double) val / 1000000);
  1094.     else
  1095.       sprintf(out, "%.1fB", (double) val / 1000000000);
  1096.   } else {
  1097.     if (val > 0 && !(val & 0x000000003fffffffULL))
  1098.       sprintf(out, "%dG", (int) (val / (1 << 30)));
  1099.     else if (val > 0 && !(val & 0x00000000000fffffULL))
  1100.       sprintf(out, "%dM", (int) (val / (1 << 20)));
  1101.     else if (val > 0 && !(val & 0x00000000000003ffULL))
  1102.       sprintf(out, "%dK", (int) (val / (1 << 10)));
  1103.     else
  1104.       sprintf(out, "%" PRIu64, val);
  1105.   }
  1106.   return out;
  1107. }
  1108.  
  1109. /*
  1110.  *******************************************************************************
  1111.  *                                                                             *
  1112.  *   DisplayTime() is used to display search times, and shows times in one of  *
  1113.  *   two ways depending on the value passed in.  If less than 60 seconds is to *
  1114.  *   be displayed, it is displayed as a decimal fraction like 32.7, while if   *
  1115.  *   more than 60 seconds is to be displayed, it is converted to the more      *
  1116.  *   traditional mm:ss form.  The string it produces is of fixed length to     *
  1117.  *   provide neater screen formatting.                                         *
  1118.  *                                                                             *
  1119.  *******************************************************************************
  1120.  */
  1121. char *DisplayTime(unsigned int time) {
  1122.   static char out[10];
  1123.  
  1124.   if (time < 6000)
  1125.     sprintf(out, "%6.2f", (float) time / 100.0);
  1126.   else {
  1127.     time = time / 100;
  1128.     sprintf(out, "%3u:%02u", time / 60, time % 60);
  1129.   }
  1130.   return out;
  1131. }
  1132.  
  1133. /*
  1134.  *******************************************************************************
  1135.  *                                                                             *
  1136.  *   Display2Times() is used to display search times, and shows times in one   *
  1137.  *   of two ways depending on the value passed in.  If less than 60 seconds is *
  1138.  *   to be displayed, it is displayed as a decimal fraction like 32.7, while   *
  1139.  *   if more than 60 seconds is to be displayed, it is converted to the more   *
  1140.  *   traditional mm:ss form.  The string it produces is of fixed length to     *
  1141.  *   provide neater screen formatting.                                         *
  1142.  *                                                                             *
  1143.  *   The second argument is the "difficulty" value which lets us display the   *
  1144.  *   target time (as modified by difficulty) so that it is possible to know    *
  1145.  *   roughly when the move will be announced.                                  *
  1146.  *                                                                             *
  1147.  *******************************************************************************
  1148.  */
  1149. char *Display2Times(unsigned int time) {
  1150.   int ttime, c, spaces;
  1151.   static char out[20], tout[10];
  1152.  
  1153.   if (time < 6000)
  1154.     sprintf(out, "%6.2f", (float) time / 100.0);
  1155.   else {
  1156.     time = time / 100;
  1157.     sprintf(out, "%3u:%02u", time / 60, time % 60);
  1158.   }
  1159.   if (search_time_limit)
  1160.     ttime = search_time_limit;
  1161.   else
  1162.     ttime = difficulty * time_limit / 100;
  1163.   if (ttime < 360000) {
  1164.     if (ttime < 6000)
  1165.       sprintf(tout, "%6.2f", (float) ttime / 100.0);
  1166.     else {
  1167.       ttime = ttime / 100;
  1168.       sprintf(tout, "%3u:%02u", ttime / 60, ttime % 60);
  1169.     }
  1170.     c = strspn(tout, " ");
  1171.     strcat(out, "/");
  1172.     strcat(out, tout + c);
  1173.   } else
  1174.     strcat(out, "       ");
  1175.   spaces = 13 - strlen(out);
  1176.   for (c = 0; c < spaces; c++)
  1177.     strcat(out, " ");
  1178.   return out;
  1179. }
  1180.  
  1181. /*
  1182.  *******************************************************************************
  1183.  *                                                                             *
  1184.  *   DisplayTimeKibitz() behaves just like DisplayTime() except that the       *
  1185.  *   string it produces is a variable-length string that is as short as        *
  1186.  *   possible to make ICC kibitzes/whispers look neater.                       *
  1187.  *                                                                             *
  1188.  *******************************************************************************
  1189.  */
  1190. char *DisplayTimeKibitz(unsigned int time) {
  1191.   static char out[10];
  1192.  
  1193.   if (time < 6000)
  1194.     sprintf(out, "%.2f", (float) time / 100.0);
  1195.   else {
  1196.     time = time / 100;
  1197.     sprintf(out, "%u:%02u", time / 60, time % 60);
  1198.   }
  1199.   return out;
  1200. }
  1201.  
  1202. /*
  1203.  *******************************************************************************
  1204.  *                                                                             *
  1205.  *   FormatPV() is used to display a PV during the search.  It will also note  *
  1206.  *   when the PV was terminated by a hash table hit.                           *
  1207.  *                                                                             *
  1208.  *******************************************************************************
  1209.  */
  1210. char *FormatPV(TREE * RESTRICT tree, int wtm, PATH pv) {
  1211.   int i, t_move_number;
  1212.   static char buffer[4096];
  1213.  
  1214. /*
  1215.  ************************************************************
  1216.  *                                                          *
  1217.  *  Initialize.                                             *
  1218.  *                                                          *
  1219.  ************************************************************
  1220.  */
  1221.   t_move_number = move_number;
  1222.   sprintf(buffer, " %d.", move_number);
  1223.   if (!wtm)
  1224.     sprintf(buffer + strlen(buffer), " ...");
  1225.   for (i = 1; i < (int) pv.pathl; i++) {
  1226.     if (i > 1 && wtm)
  1227.       sprintf(buffer + strlen(buffer), " %d.", t_move_number);
  1228.     sprintf(buffer + strlen(buffer), " %s", OutputMove(tree, i, wtm,
  1229.             pv.path[i]));
  1230.     MakeMove(tree, i, wtm, pv.path[i]);
  1231.     wtm = Flip(wtm);
  1232.     if (wtm)
  1233.       t_move_number++;
  1234.   }
  1235.   for (i = pv.pathl - 1; i > 0; i--) {
  1236.     wtm = Flip(wtm);
  1237.     UnmakeMove(tree, i, wtm, pv.path[i]);
  1238.   }
  1239.   return buffer;
  1240. }
  1241.  
  1242. /* last modified 02/26/14 */
  1243. /*
  1244.  *******************************************************************************
  1245.  *                                                                             *
  1246.  *   GameOver() is used to determine if the game is over by rule.  More        *
  1247.  *   specifically, after our move, the opponent has no legal move to play.  He *
  1248.  *   is either checkmated or stalemated, either of which is sufficient reason  *
  1249.  *   to terminate the game.                                                    *
  1250.  *                                                                             *
  1251.  *******************************************************************************
  1252.  */
  1253. int GameOver(int wtm) {
  1254.   TREE *const tree = block[0];
  1255.   unsigned *mvp, *lastm, rmoves[256], over = 1;
  1256.  
  1257. /*
  1258.  ************************************************************
  1259.  *                                                          *
  1260.  *  First, use GenerateMoves() to generate the set of       *
  1261.  *  legal moves from the root position.                     *
  1262.  *                                                          *
  1263.  ************************************************************
  1264.  */
  1265.   lastm = GenerateCaptures(tree, 1, wtm, rmoves);
  1266.   lastm = GenerateNoncaptures(tree, 1, wtm, lastm);
  1267. /*
  1268.  ************************************************************
  1269.  *                                                          *
  1270.  *  Now make each move and determine if we are in check     *
  1271.  *  after each one.  Any move that does not leave us in     *
  1272.  *  check is good enough to prove that the game is not yet  *
  1273.  *  officially over.                                        *
  1274.  *                                                          *
  1275.  ************************************************************
  1276.  */
  1277.   for (mvp = rmoves; mvp < lastm; mvp++) {
  1278.     MakeMove(tree, 1, wtm, *mvp);
  1279.     if (!Check(wtm))
  1280.       over = 0;
  1281.     UnmakeMove(tree, 1, wtm, *mvp);
  1282.   }
  1283. /*
  1284.  ************************************************************
  1285.  *                                                          *
  1286.  *  If we did not make it thru the complete move list, we   *
  1287.  *  must have at least one legal move so the game is not    *
  1288.  *  over.  return 0.  Otherwise, we have no move and the    *
  1289.  *  game is over.  We return 1 if this side is stalmated or *
  1290.  *  we return 2 if this side is mated.                      *
  1291.  *                                                          *
  1292.  ************************************************************
  1293.  */
  1294.   if (!over)
  1295.     return 0;
  1296.   else if (!Check(wtm))
  1297.     return 1;
  1298.   else
  1299.     return 2;
  1300. }
  1301.  
  1302. /*
  1303.  *******************************************************************************
  1304.  *                                                                             *
  1305.  *   ReadClock() is a procedure used to read the elapsed time.  Since this     *
  1306.  *   varies from system to system, this procedure has several flavors to       *
  1307.  *   provide portability.                                                      *
  1308.  *                                                                             *
  1309.  *******************************************************************************
  1310.  */
  1311. unsigned int ReadClock(void) {
  1312. #if defined(UNIX)
  1313.   struct timeval timeval;
  1314.   struct timezone timezone;
  1315. #endif
  1316. #if defined(UNIX)
  1317.   gettimeofday(&timeval, &timezone);
  1318.   return timeval.tv_sec * 100 + (timeval.tv_usec / 10000);
  1319. #else
  1320.   return (unsigned int) GetTickCount() / 10;
  1321. #endif
  1322. }
  1323.  
  1324. /*
  1325.  *******************************************************************************
  1326.  *                                                                             *
  1327.  *   FindBlockID() converts a thread block pointer into an ID that is easier   *
  1328.  *   to understand when debugging.                                             *
  1329.  *                                                                             *
  1330.  *******************************************************************************
  1331.  */
  1332. int FindBlockID(TREE * RESTRICT which) {
  1333.   int i;
  1334.  
  1335.   for (i = 0; i <= smp_max_threads * 64; i++)
  1336.     if (which == block[i])
  1337.       return i;
  1338.   return -1;
  1339. }
  1340.  
  1341. /*
  1342.  *******************************************************************************
  1343.  *                                                                             *
  1344.  *   InvalidPosition() is used to determine if the position just entered via a *
  1345.  *   FEN-string or the "edit" command is legal.  This includes the expected    *
  1346.  *   tests for too many pawns or pieces for one side, pawns on impossible      *
  1347.  *   squares, and the like.                                                    *
  1348.  *                                                                             *
  1349.  *******************************************************************************
  1350.  */
  1351. int InvalidPosition(TREE * RESTRICT tree) {
  1352.   int error = 0, wp, wn, wb, wr, wq, wk, bp, bn, bb, br, bq, bk;
  1353.  
  1354.   wp = PopCnt(Pawns(white));
  1355.   wn = PopCnt(Knights(white));
  1356.   wb = PopCnt(Bishops(white));
  1357.   wr = PopCnt(Rooks(white));
  1358.   wq = PopCnt(Queens(white));
  1359.   wk = PopCnt(Kings(white));
  1360.   bp = PopCnt(Pawns(black));
  1361.   bn = PopCnt(Knights(black));
  1362.   bb = PopCnt(Bishops(black));
  1363.   br = PopCnt(Rooks(black));
  1364.   bq = PopCnt(Queens(black));
  1365.   bk = PopCnt(Kings(black));
  1366.   if (wp > 8) {
  1367.     Print(4095, "illegal position, too many white pawns\n");
  1368.     error = 1;
  1369.   }
  1370.   if (wn && wp + wn > 10) {
  1371.     Print(4095, "illegal position, too many white knights\n");
  1372.     error = 1;
  1373.   }
  1374.   if (wb && wp + wb > 10) {
  1375.     Print(4095, "illegal position, too many white bishops\n");
  1376.     error = 1;
  1377.   }
  1378.   if (wr && wp + wr > 10) {
  1379.     Print(4095, "illegal position, too many white rooks\n");
  1380.     error = 1;
  1381.   }
  1382.   if (wq && wp + wq > 10) {
  1383.     Print(4095, "illegal position, too many white queens\n");
  1384.     error = 1;
  1385.   }
  1386.   if (wk == 0) {
  1387.     Print(4095, "illegal position, no white king\n");
  1388.     error = 1;
  1389.   }
  1390.   if (wk > 1) {
  1391.     Print(4095, "illegal position, multiple white kings\n");
  1392.     error = 1;
  1393.   }
  1394.   if ((wn + wb + wr + wq) && wp + wn + wb + wr + wq > 15) {
  1395.     Print(4095, "illegal position, too many white pieces\n");
  1396.     error = 1;
  1397.   }
  1398.   if (Pawns(white) & (rank_mask[RANK1] | rank_mask[RANK8])) {
  1399.     Print(4095, "illegal position, white pawns on first/eighth rank(s)\n");
  1400.     error = 1;
  1401.   }
  1402.   if (bp > 8) {
  1403.     Print(4095, "illegal position, too many black pawns\n");
  1404.     error = 1;
  1405.   }
  1406.   if (bn && bp + bn > 10) {
  1407.     Print(4095, "illegal position, too many black knights\n");
  1408.     error = 1;
  1409.   }
  1410.   if (bb && bp + bb > 10) {
  1411.     Print(4095, "illegal position, too many black bishops\n");
  1412.     error = 1;
  1413.   }
  1414.   if (br && bp + br > 10) {
  1415.     Print(4095, "illegal position, too many black rooks\n");
  1416.     error = 1;
  1417.   }
  1418.   if (bq && bp + bq > 10) {
  1419.     Print(4095, "illegal position, too many black queens\n");
  1420.     error = 1;
  1421.   }
  1422.   if (bk == 0) {
  1423.     Print(4095, "illegal position, no black king\n");
  1424.     error = 1;
  1425.   }
  1426.   if (bk > 1) {
  1427.     Print(4095, "illegal position, multiple black kings\n");
  1428.     error = 1;
  1429.   }
  1430.   if ((bn + bb + br + bq) && bp + bn + bb + br + bq > 15) {
  1431.     Print(4095, "illegal position, too many black pieces\n");
  1432.     error = 1;
  1433.   }
  1434.   if (Pawns(black) & (rank_mask[RANK1] | rank_mask[RANK8])) {
  1435.     Print(4095, "illegal position, black pawns on first/eighth rank(s)\n");
  1436.     error = 1;
  1437.   }
  1438.   if (error == 0 && Check(!game_wtm)) {
  1439.     Print(4095, "ERROR side not on move is in check!\n");
  1440.     error = 1;
  1441.   }
  1442.   return error;
  1443. }
  1444.  
  1445. /*
  1446.  *******************************************************************************
  1447.  *                                                                             *
  1448.  *   KingPawnSquare() is used to initialize some of the passed pawn race       *
  1449.  *   tables used by Evaluate().  It simply answers the question "is the king   *
  1450.  *   in the square of the pawn so the pawn can't outrun it and promote?"       *
  1451.  *                                                                             *
  1452.  *******************************************************************************
  1453.  */
  1454. int KingPawnSquare(int pawn, int king, int queen, int ptm) {
  1455.   int pdist, kdist;
  1456.  
  1457.   pdist = Abs(Rank(pawn) - Rank(queen)) + !ptm;
  1458.   kdist = Distance(king, queen);
  1459.   return pdist >= kdist;
  1460. }
  1461.  
  1462. /* last modified 07/13/16 */
  1463. /*
  1464.  *******************************************************************************
  1465.  *                                                                             *
  1466.  *   Mated() is used to determine if the game has ended by checkmate.          *
  1467.  *                                                                             *
  1468.  *   We return 0 if the game doesn't end here, 1 if the side on move is mated  *
  1469.  *   and 2 if the side on move is stalemated.                                  *
  1470.  *                                                                             *
  1471.  *******************************************************************************
  1472.  */
  1473. int Mated(TREE * RESTRICT tree, int ply, int wtm) {
  1474.   unsigned int rmoves[256], *mvp, *lastm;
  1475.   int temp = 0;
  1476.  
  1477. /*
  1478.  ************************************************************
  1479.  *                                                          *
  1480.  *   first, use GenerateMoves() to generate the set of      *
  1481.  *   legal moves from the root position, after making the   *
  1482.  *   test move passed in.                                   *
  1483.  *                                                          *
  1484.  ************************************************************
  1485.  */
  1486.   lastm = GenerateCaptures(tree, ply, wtm, rmoves);
  1487.   lastm = GenerateNoncaptures(tree, ply, wtm, lastm);
  1488. /*
  1489.  ************************************************************
  1490.  *                                                          *
  1491.  *   now make each move and use eliminate any that leave    *
  1492.  *   king in check (which makes those moves illegal.)       *
  1493.  *                                                          *
  1494.  ************************************************************
  1495.  */
  1496.   for (mvp = rmoves; mvp < lastm; mvp++) {
  1497.     MakeMove(tree, ply, wtm, *mvp);
  1498.     temp = Check(wtm);
  1499.     UnmakeMove(tree, ply, wtm, *mvp);
  1500.     if (!temp)
  1501.       break;
  1502.   }
  1503. /*
  1504.  ************************************************************
  1505.  *                                                          *
  1506.  *   if there is one move that did not leave us in check,   *
  1507.  *   then it can't be checkmate/stalemate.                  *
  1508.  *                                                          *
  1509.  ************************************************************
  1510.  */
  1511.   if (!temp)
  1512.     return 0;
  1513. /*
  1514.  ************************************************************
  1515.  *                                                          *
  1516.  *   No legal moves.  If we are in check, we have been      *
  1517.  *   checkmated, otherwise we are stalemated.               *
  1518.  *                                                          *
  1519.  ************************************************************
  1520.  */
  1521.   if (Check(wtm))
  1522.     return 1;
  1523.   return 2;
  1524. }
  1525.  
  1526. /*
  1527.  *******************************************************************************
  1528.  *                                                                             *
  1529.  *   ParseTime() is used to parse a time value that could be entered as s.ss,  *
  1530.  *   mm:ss, or hh:mm:ss.  It is converted to Crafty's internal 1/100th second  *
  1531.  *   time resolution.                                                          *
  1532.  *                                                                             *
  1533.  *******************************************************************************
  1534.  */
  1535. int ParseTime(char *string) {
  1536.   int time = 0, minutes = 0;
  1537.  
  1538.   while (*string) {
  1539.     switch (*string) {
  1540.       case '0':
  1541.       case '1':
  1542.       case '2':
  1543.       case '3':
  1544.       case '4':
  1545.       case '5':
  1546.       case '6':
  1547.       case '7':
  1548.       case '8':
  1549.       case '9':
  1550.         minutes = minutes * 10 + (*string) - '0';
  1551.         break;
  1552.       case ':':
  1553.         time = time * 60 + minutes;
  1554.         minutes = 0;
  1555.         break;
  1556.       default:
  1557.         Print(4095, "illegal character in time, please re-enter\n");
  1558.         break;
  1559.     }
  1560.     string++;
  1561.   }
  1562.   return time * 60 + minutes;
  1563. }
  1564.  
  1565. /*
  1566.  *******************************************************************************
  1567.  *                                                                             *
  1568.  *   Pass() was written by Tim Mann to handle the case where a position is set *
  1569.  *   using a FEN string, and then black moves first.  The game.nnn file was    *
  1570.  *   designed to start with a white move, so "pass" is now a "no-op" move for  *
  1571.  *   the side whose turn it is to move.                                        *
  1572.  *                                                                             *
  1573.  *******************************************************************************
  1574.  */
  1575. void Pass(void) {
  1576.   const int halfmoves_done = 2 * (move_number - 1) + (1 - game_wtm);
  1577.   int prev_pass = 0;
  1578.   char buffer[128];
  1579.  
  1580. /* Was previous move a pass? */
  1581.   if (halfmoves_done > 0) {
  1582.     if (history_file) {
  1583.       fseek(history_file, (halfmoves_done - 1) * 10, SEEK_SET);
  1584.       if (fscanf(history_file, "%s", buffer) == 0 ||
  1585.           strcmp(buffer, "pass") == 0)
  1586.         prev_pass = 1;
  1587.     }
  1588.   }
  1589.   if (prev_pass) {
  1590.     if (game_wtm)
  1591.       move_number--;
  1592.   } else {
  1593.     if (history_file) {
  1594.       fseek(history_file, halfmoves_done * 10, SEEK_SET);
  1595.       fprintf(history_file, "%9s\n", "pass");
  1596.     }
  1597.     if (!game_wtm)
  1598.       move_number++;
  1599.   }
  1600.   game_wtm = Flip(game_wtm);
  1601. }
  1602.  
  1603. /*
  1604.  *******************************************************************************
  1605.  *                                                                             *
  1606.  *   Print() is the main output procedure.  The first argument is a bitmask    *
  1607.  *   that identifies the type of output.  If this argument is anded with the   *
  1608.  *   "display" control variable, and a non-zero result is produced, then the   *
  1609.  *   print is done, otherwise the print is skipped and we return (more details *
  1610.  *   can be found in the display command comments in option.c).  This also     *
  1611.  *   uses the "variable number of arguments" facility in ANSI C since the      *
  1612.  *   normal printf() function accepts a variable number of arguments.          *
  1613.  *                                                                             *
  1614.  *   Print() also sends output to the log.nnn file automatically, so that it   *
  1615.  *   is recorded even if the above display control variable says "do not send  *
  1616.  *   this to stdout"                                                           *
  1617.  *                                                                             *
  1618.  *******************************************************************************
  1619.  */
  1620. void Print(int vb, char *fmt, ...) {
  1621.   va_list ap;
  1622.  
  1623.   va_start(ap, fmt);
  1624.   if (vb == 4095 || vb & display_options) {
  1625.     vprintf(fmt, ap);
  1626.     fflush(stdout);
  1627.   }
  1628.   if (time_limit > 5 || tc_time_remaining[root_wtm] > 1000 || vb == 4095) {
  1629.     va_start(ap, fmt);
  1630.     if (log_file) {
  1631.       vfprintf(log_file, fmt, ap);
  1632.       fflush(log_file);
  1633.     }
  1634.   }
  1635.   va_end(ap);
  1636. }
  1637.  
  1638. /*
  1639.  *******************************************************************************
  1640.  *                                                                             *
  1641.  *  A 32 bit random number generator. An implementation in C of the algorithm  *
  1642.  *  given by Knuth, the art of computer programming, vol. 2, pp. 26-27. We use *
  1643.  *  e=32, so we have to evaluate y(n) = y(n - 24) + y(n - 55) mod 2^32, which  *
  1644.  *  is implicitly done by unsigned arithmetic.                                 *
  1645.  *                                                                             *
  1646.  *******************************************************************************
  1647.  */
  1648. unsigned int Random32(void) {
  1649. /*
  1650.  random numbers from Mathematica 2.0.
  1651.  SeedRandom = 1;
  1652.  Table[Random[Integer, {0, 2^32 - 1}]
  1653.  */
  1654.   static const uint64_t x[55] = {
  1655.     1410651636UL, 3012776752UL, 3497475623UL, 2892145026UL, 1571949714UL,
  1656.     3253082284UL, 3489895018UL, 387949491UL, 2597396737UL, 1981903553UL,
  1657.     3160251843UL, 129444464UL, 1851443344UL, 4156445905UL, 224604922UL,
  1658.     1455067070UL, 3953493484UL, 1460937157UL, 2528362617UL, 317430674UL,
  1659.     3229354360UL, 117491133UL, 832845075UL, 1961600170UL, 1321557429UL,
  1660.     747750121UL, 545747446UL, 810476036UL, 503334515UL, 4088144633UL,
  1661.     2824216555UL, 3738252341UL, 3493754131UL, 3672533954UL, 29494241UL,
  1662.     1180928407UL, 4213624418UL, 33062851UL, 3221315737UL, 1145213552UL,
  1663.     2957984897UL, 4078668503UL, 2262661702UL, 65478801UL, 2527208841UL,
  1664.     1960622036UL, 315685891UL, 1196037864UL, 804614524UL, 1421733266UL,
  1665.     2017105031UL, 3882325900UL, 810735053UL, 384606609UL, 2393861397UL
  1666.   };
  1667.   static int init = 1;
  1668.   static uint64_t y[55];
  1669.   static int j, k;
  1670.   uint64_t ul;
  1671.  
  1672.   if (init) {
  1673.     int i;
  1674.  
  1675.     init = 0;
  1676.     for (i = 0; i < 55; i++)
  1677.       y[i] = x[i];
  1678.     j = 24 - 1;
  1679.     k = 55 - 1;
  1680.   }
  1681.   ul = (y[k] += y[j]);
  1682.   if (--j < 0)
  1683.     j = 55 - 1;
  1684.   if (--k < 0)
  1685.     k = 55 - 1;
  1686.   return (unsigned int) ul;
  1687. }
  1688.  
  1689. /*
  1690.  *******************************************************************************
  1691.  *                                                                             *
  1692.  *   Random64() uses two calls to Random32() and then concatenates the two     *
  1693.  *   values into one 64 bit random number, used for hash signature updates on  *
  1694.  *   the Zobrist hash signatures.                                              *
  1695.  *                                                                             *
  1696.  *******************************************************************************
  1697.  */
  1698. uint64_t Random64(void) {
  1699.   uint64_t result;
  1700.   unsigned int r1, r2;
  1701.  
  1702.   r1 = Random32();
  1703.   r2 = Random32();
  1704.   result = r1 | (uint64_t) r2 << 32;
  1705.   return result;
  1706. }
  1707.  
  1708. /*
  1709.  *******************************************************************************
  1710.  *                                                                             *
  1711.  *   Read() copies data from the command_buffer into a local buffer, and then  *
  1712.  *   uses ReadParse to break this command up into tokens for processing.       *
  1713.  *                                                                             *
  1714.  *******************************************************************************
  1715.  */
  1716. int Read(int wait, char *buffer) {
  1717.   char *eol, *ret, readdata;
  1718.  
  1719.   *buffer = 0;
  1720. /*
  1721.  case 1:  We have a complete command line, with terminating
  1722.  N/L character in the buffer.  We can simply extract it from
  1723.  the I/O buffer, parse it and return.
  1724.  */
  1725.   if (strchr(cmd_buffer, '\n'));
  1726. /*
  1727.  case 2:  The buffer does not contain a complete line.  If we
  1728.  were asked to not wait for a complete command, then we first
  1729.  see if I/O is possible, and if so, read in what is available.
  1730.  If that includes a N/L, then we are ready to parse and return.
  1731.  If not, we return indicating no input available just yet.
  1732.  */
  1733.   else if (!wait) {
  1734.     if (CheckInput()) {
  1735.       readdata = ReadInput();
  1736.       if (!strchr(cmd_buffer, '\n'))
  1737.         return 0;
  1738.       if (!readdata)
  1739.         return -1;
  1740.     } else
  1741.       return 0;
  1742.   }
  1743. /*
  1744.  case 3:  The buffer does not contain a complete line, but we
  1745.  were asked to wait until a complete command is entered.  So we
  1746.  hang by doing a ReadInput() and continue doing so until we get
  1747.  a N/L character in the buffer.  Then we parse and return.
  1748.  */
  1749.   else
  1750.     while (!strchr(cmd_buffer, '\n')) {
  1751.       readdata = ReadInput();
  1752.       if (!readdata)
  1753.         return -1;
  1754.     }
  1755.   eol = strchr(cmd_buffer, '\n');
  1756.   *eol = 0;
  1757.   ret = strchr(cmd_buffer, '\r');
  1758.   if (ret)
  1759.     *ret = ' ';
  1760.   strcpy(buffer, cmd_buffer);
  1761.   memmove(cmd_buffer, eol + 1, strlen(eol + 1) + 1);
  1762.   return 1;
  1763. }
  1764.  
  1765. /*
  1766.  *******************************************************************************
  1767.  *                                                                             *
  1768.  *   ReadClear() clears the input buffer when input_stream is being switched   *
  1769.  *   to a file, since we have info buffered up from a different input stream.  *
  1770.  *                                                                             *
  1771.  *******************************************************************************
  1772.  */
  1773. void ReadClear() {
  1774.   cmd_buffer[0] = 0;
  1775. }
  1776.  
  1777. /*
  1778.  *******************************************************************************
  1779.  *                                                                             *
  1780.  *   ReadParse() takes one complete command-line, and breaks it up into tokens.*
  1781.  *   common delimiters are used, such as " ", ",", "/" and ";", any of which   *
  1782.  *   delimit fields.                                                           *
  1783.  *                                                                             *
  1784.  *******************************************************************************
  1785.  */
  1786. int ReadParse(char *buffer, char *args[], char *delims) {
  1787.   int nargs;
  1788.   char *next, tbuffer[4096];
  1789.  
  1790.   strcpy(tbuffer, buffer);
  1791.   for (nargs = 0; nargs < 512; nargs++)
  1792.     *(args[nargs]) = 0;
  1793.   next = strtok(tbuffer, delims);
  1794.   if (!next)
  1795.     return 0;
  1796.   if (strlen(next) > 255)
  1797.     Print(4095, "ERROR, ignoring token %s, max allowable len = 255\n", next);
  1798.   else
  1799.     strcpy(args[0], next);
  1800.   for (nargs = 1; nargs < 512; nargs++) {
  1801.     next = strtok(0, delims);
  1802.     if (!next)
  1803.       break;
  1804.     if (strlen(next) > 255)
  1805.       Print(4095, "ERROR, ignoring token %s, max allowable len = 255\n",
  1806.           next);
  1807.     else
  1808.       strcpy(args[nargs], next);
  1809.   }
  1810.   return nargs;
  1811. }
  1812.  
  1813. /*
  1814.  *******************************************************************************
  1815.  *                                                                             *
  1816.  *   ReadInput() reads data from the input_stream, and buffers this into the   *
  1817.  *   command_buffer for later processing.                                      *
  1818.  *                                                                             *
  1819.  *******************************************************************************
  1820.  */
  1821. int ReadInput(void) {
  1822.   int bytes;
  1823.   char buffer[4096], *end;
  1824.  
  1825.   do
  1826.     bytes = _read(_fileno(input_stream), buffer, 2048); // Pierre-Marie Baty -- ISO C++ name conformance fixes
  1827.   while (bytes < 0 && errno == EINTR);
  1828.   if (bytes == 0) {
  1829.     if (input_stream != stdin)
  1830.       fclose(input_stream);
  1831.     input_stream = stdin;
  1832.     return 0;
  1833.   } else if (bytes < 0) {
  1834.     Print(4095, "ERROR!  input I/O stream is unreadable, exiting.\n");
  1835.     CraftyExit(1);
  1836.   }
  1837.   end = cmd_buffer + strlen(cmd_buffer);
  1838.   memcpy(end, buffer, bytes);
  1839.   *(end + bytes) = 0;
  1840.   return 1;
  1841. }
  1842.  
  1843. /*
  1844.  *******************************************************************************
  1845.  *                                                                             *
  1846.  *   ReadChessMove() is used to read a move from an input file.  The main      *
  1847.  *   issue is to skip over "trash" like move numbers, times, comments, and so  *
  1848.  *   forth, and find the next actual move.                                     *
  1849.  *                                                                             *
  1850.  *******************************************************************************
  1851.  */
  1852. int ReadChessMove(TREE * RESTRICT tree, FILE * input, int wtm, int one_move) {
  1853.   int move = 0, status;
  1854.   static char text[128];
  1855.   char *tmove;
  1856.  
  1857.   while (move == 0) {
  1858.     status = fscanf(input, "%s", text);
  1859.     if (status <= 0)
  1860.       return -1;
  1861.     if (strcmp(text, "0-0") && strcmp(text, "0-0-0"))
  1862.       tmove = text + strspn(text, "0123456789.");
  1863.     else
  1864.       tmove = text;
  1865.     if (((tmove[0] >= 'a' && tmove[0] <= 'z') || (tmove[0] >= 'A' &&
  1866.                 tmove[0] <= 'Z')) || !strcmp(tmove, "0-0")
  1867.         || !strcmp(tmove, "0-0-0")) {
  1868.       if (!strcmp(tmove, "exit"))
  1869.         return -1;
  1870.       move = InputMove(tree, 0, wtm, 1, 0, tmove);
  1871.     }
  1872.     if (one_move)
  1873.       break;
  1874.   }
  1875.   return move;
  1876. }
  1877.  
  1878. /*
  1879.  *******************************************************************************
  1880.  *                                                                             *
  1881.  *   ReadNextMove() is used to take a text chess move from a file, and see if  *
  1882.  *   if is legal, skipping a sometimes embedded move number (1.e4 for example) *
  1883.  *   to make PGN import easier.                                                *
  1884.  *                                                                             *
  1885.  *******************************************************************************
  1886.  */
  1887. int ReadNextMove(TREE * RESTRICT tree, char *text, int ply, int wtm) {
  1888.   char *tmove;
  1889.   int move = 0;
  1890.  
  1891.   if (strcmp(text, "0-0") && strcmp(text, "0-0-0"))
  1892.     tmove = text + strspn(text, "0123456789./-");
  1893.   else
  1894.     tmove = text;
  1895.   if (((tmove[0] >= 'a' && tmove[0] <= 'z') || (tmove[0] >= 'A' &&
  1896.               tmove[0] <= 'Z')) || !strcmp(tmove, "0-0")
  1897.       || !strcmp(tmove, "0-0-0")) {
  1898.     if (!strcmp(tmove, "exit"))
  1899.       return -1;
  1900.     move = InputMove(tree, ply, wtm, 1, 0, tmove);
  1901.   }
  1902.   return move;
  1903. }
  1904.  
  1905. /*
  1906.  *******************************************************************************
  1907.  *                                                                             *
  1908.  *   This routine reads a move from a PGN file to build an opening book or for *
  1909.  *   annotating.  It returns a 1 if a header is read, it returns a 0 if a move *
  1910.  *   is read, and returns a -1 on end of file.  It counts lines and this       *
  1911.  *   counter can be accessed by calling this function with a non-zero second   *
  1912.  *   formal parameter.                                                         *
  1913.  *                                                                             *
  1914.  *******************************************************************************
  1915.  */
  1916. int ReadPGN(FILE * input, int option) {
  1917.   static int data = 0, lines_read = 0;
  1918.   int braces = 0, parens = 0, brackets = 0, analysis = 0, last_good_line;
  1919.   static char input_buffer[4096];
  1920.   char *eof, analysis_move[64];
  1921.  
  1922. /*
  1923.  ************************************************************
  1924.  *                                                          *
  1925.  *  If the line counter is being requested, return it with  *
  1926.  *  no other changes being made.  If "purge" is true, clear *
  1927.  *  the current input buffer.                               *
  1928.  *                                                          *
  1929.  ************************************************************
  1930.  */
  1931.   pgn_suggested_percent = 0;
  1932.   if (!input) {
  1933.     lines_read = 0;
  1934.     data = 0;
  1935.     return 0;
  1936.   }
  1937.   if (option == -1)
  1938.     data = 0;
  1939.   if (option == -2)
  1940.     return lines_read;
  1941. /*
  1942.  ************************************************************
  1943.  *                                                          *
  1944.  *  If we don't have any data in the buffer, the first step *
  1945.  *  is to read the next line.                               *
  1946.  *                                                          *
  1947.  ************************************************************
  1948.  */
  1949.   while (FOREVER) {
  1950.     if (!data) {
  1951.       eof = fgets(input_buffer, 4096, input);
  1952.       if (!eof)
  1953.         return -1;
  1954.       if (strchr(input_buffer, '\n'))
  1955.         *strchr(input_buffer, '\n') = 0;
  1956.       if (strchr(input_buffer, '\r'))
  1957.         *strchr(input_buffer, '\r') = ' ';
  1958.       lines_read++;
  1959.       buffer[0] = 0;
  1960.       sscanf(input_buffer, "%s", buffer);
  1961.       if (buffer[0] == '[')
  1962.         do {
  1963.           char *bracket1, *bracket2, value[128];
  1964.  
  1965.           strcpy(buffer, input_buffer);
  1966.           bracket1 = strchr(input_buffer, '\"');
  1967.           if (bracket1 == 0)
  1968.             return 1;
  1969.           bracket2 = strchr(bracket1 + 1, '\"');
  1970.           if (bracket2 == 0)
  1971.             return 1;
  1972.           *bracket1 = 0;
  1973.           *bracket2 = 0;
  1974.           strcpy(value, bracket1 + 1);
  1975.           if (strstr(input_buffer, "Event"))
  1976.             strcpy(pgn_event, value);
  1977.           else if (strstr(input_buffer, "Site"))
  1978.             strcpy(pgn_site, value);
  1979.           else if (strstr(input_buffer, "Round"))
  1980.             strcpy(pgn_round, value);
  1981.           else if (strstr(input_buffer, "Date"))
  1982.             strcpy(pgn_date, value);
  1983.           else if (strstr(input_buffer, "WhiteElo"))
  1984.             strcpy(pgn_white_elo, value);
  1985.           else if (strstr(input_buffer, "White"))
  1986.             strcpy(pgn_white, value);
  1987.           else if (strstr(input_buffer, "BlackElo"))
  1988.             strcpy(pgn_black_elo, value);
  1989.           else if (strstr(input_buffer, "Black"))
  1990.             strcpy(pgn_black, value);
  1991.           else if (strstr(input_buffer, "Result"))
  1992.             strcpy(pgn_result, value);
  1993.           else if (strstr(input_buffer, "FEN")) {
  1994.             sprintf(buffer, "setboard %s", value);
  1995.             Option(block[0]);
  1996.             continue;
  1997.           }
  1998.           return 1;
  1999.         } while (0);
  2000.       data = 1;
  2001.     }
  2002. /*
  2003.  ************************************************************
  2004.  *                                                          *
  2005.  *  If we already have data in the buffer, it is just a     *
  2006.  *  matter of extracting the next move and returning it to  *
  2007.  *  the caller.  If the buffer is empty, another line has   *
  2008.  *  to be read in.                                          *
  2009.  *                                                          *
  2010.  ************************************************************
  2011.  */
  2012.     else {
  2013.       buffer[0] = 0;
  2014.       sscanf(input_buffer, "%s", buffer);
  2015.       if (strlen(buffer) == 0) {
  2016.         data = 0;
  2017.         continue;
  2018.       } else {
  2019.         char *skip;
  2020.  
  2021.         skip = strstr(input_buffer, buffer) + strlen(buffer);
  2022.         if (skip)
  2023.           memmove(input_buffer, skip, strlen(skip) + 1);
  2024.       }
  2025. /*
  2026.  ************************************************************
  2027.  *                                                          *
  2028.  *  This skips over nested {} or () characters and finds    *
  2029.  *  the 'mate', before returning any more moves.  It also   *
  2030.  *  stops if a PGN header is encountered, probably due to   *
  2031.  *  an incorrectly bracketed analysis variation.            *
  2032.  *                                                          *
  2033.  ************************************************************
  2034.  */
  2035.       last_good_line = lines_read;
  2036.       analysis_move[0] = 0;
  2037.       if (strchr(buffer, '{') || strchr(buffer, '('))
  2038.         while (FOREVER) {
  2039.           char *skip, *ch;
  2040.  
  2041.           analysis = 1;
  2042.           while ((ch = strpbrk(buffer, "(){}[]"))) {
  2043.             if (*ch == '(') {
  2044.               *strchr(buffer, '(') = ' ';
  2045.               if (!braces)
  2046.                 parens++;
  2047.             }
  2048.             if (*ch == ')') {
  2049.               *strchr(buffer, ')') = ' ';
  2050.               if (!braces)
  2051.                 parens--;
  2052.             }
  2053.             if (*ch == '{') {
  2054.               *strchr(buffer, '{') = ' ';
  2055.               braces++;
  2056.             }
  2057.             if (*ch == '}') {
  2058.               *strchr(buffer, '}') = ' ';
  2059.               braces--;
  2060.             }
  2061.             if (*ch == '[') {
  2062.               *strchr(buffer, '[') = ' ';
  2063.               if (!braces)
  2064.                 brackets++;
  2065.             }
  2066.             if (*ch == ']') {
  2067.               *strchr(buffer, ']') = ' ';
  2068.               if (!braces)
  2069.                 brackets--;
  2070.             }
  2071.           }
  2072.           if (analysis && analysis_move[0] == 0) {
  2073.             if (strspn(buffer, " ") != strlen(buffer)) {
  2074.               char *tmove = analysis_move;
  2075.  
  2076.               sscanf(buffer, "%64s", analysis_move);
  2077.               strcpy(buffer, analysis_move);
  2078.               if (strcmp(buffer, "0-0") && strcmp(buffer, "0-0-0"))
  2079.                 tmove = buffer + strspn(buffer, "0123456789.");
  2080.               else
  2081.                 tmove = buffer;
  2082.               if ((tmove[0] >= 'a' && tmove[0] <= 'z') || (tmove[0] >= 'A' &&
  2083.                       tmove[0] <= 'Z') || !strcmp(tmove, "0-0")
  2084.                   || !strcmp(tmove, "0-0-0"))
  2085.                 strcpy(analysis_move, buffer);
  2086.               else
  2087.                 analysis_move[0] = 0;
  2088.             }
  2089.           }
  2090.           if (parens == 0 && braces == 0 && brackets == 0)
  2091.             break;
  2092.           buffer[0] = 0;
  2093.           sscanf(input_buffer, "%s", buffer);
  2094.           if (strlen(buffer) == 0) {
  2095.             eof = fgets(input_buffer, 4096, input);
  2096.             if (!eof) {
  2097.               parens = 0;
  2098.               braces = 0;
  2099.               brackets = 0;
  2100.               return -1;
  2101.             }
  2102.             if (strchr(input_buffer, '\n'))
  2103.               *strchr(input_buffer, '\n') = 0;
  2104.             if (strchr(input_buffer, '\r'))
  2105.               *strchr(input_buffer, '\r') = ' ';
  2106.             lines_read++;
  2107.             if (lines_read - last_good_line >= 100) {
  2108.               parens = 0;
  2109.               braces = 0;
  2110.               brackets = 0;
  2111.               Print(4095,
  2112.                   "ERROR.  comment spans over 100 lines, starting at line %d\n",
  2113.                   last_good_line);
  2114.               break;
  2115.             }
  2116.           }
  2117.           skip = strstr(input_buffer, buffer) + strlen(buffer);
  2118.           memmove(input_buffer, skip, strlen(skip) + 1);
  2119.       } else {
  2120.         int skip;
  2121.  
  2122.         if ((skip = strspn(buffer, "0123456789./-"))) {
  2123.           if (skip > 1)
  2124.             memmove(buffer, buffer + skip, strlen(buffer + skip) + 1);
  2125.         }
  2126.         if (isalpha(buffer[0]) || strchr(buffer, '-')) {
  2127.           char *first, *last, *percent;
  2128.  
  2129.           first = input_buffer + strspn(input_buffer, " ");
  2130.           if (first == 0 || *first != '{')
  2131.             return 0;
  2132.           last = strchr(input_buffer, '}');
  2133.           if (last == 0)
  2134.             return 0;
  2135.           percent = strstr(first, "play");
  2136.           if (percent == 0)
  2137.             return 0;
  2138.           pgn_suggested_percent =
  2139.               atoi(percent + 4 + strspn(percent + 4, " "));
  2140.           return 0;
  2141.         }
  2142.       }
  2143.       if (analysis_move[0] && option == 1) {
  2144.         strcpy(buffer, analysis_move);
  2145.         return 2;
  2146.       }
  2147.     }
  2148.   }
  2149. }
  2150.  
  2151. /*
  2152.  *******************************************************************************
  2153.  *                                                                             *
  2154.  *   RestoreGame() resets the position to the beginning of the game, and then  *
  2155.  *   reads in the game.nnn history file to set the position up so that the     *
  2156.  *   game position matches the position at the end of the history file.        *
  2157.  *                                                                             *
  2158.  *******************************************************************************
  2159.  */
  2160. void RestoreGame(void) {
  2161.   int i, v, move;
  2162.   char cmd[16];
  2163.  
  2164.   if (!history_file)
  2165.     return;
  2166.   game_wtm = 1;
  2167.   InitializeChessBoard(block[0]);
  2168.   for (i = 0; i < 500; i++) {
  2169.     fseek(history_file, i * 10, SEEK_SET);
  2170.     strcpy(cmd, "");
  2171.     v = fscanf(history_file, "%s", cmd);
  2172.     if (v < 0)
  2173.       perror("RestoreGame fscanf error: ");
  2174.     if (strcmp(cmd, "pass")) {
  2175.       move = InputMove(block[0], 0, game_wtm, 1, 0, cmd);
  2176.       if (move)
  2177.         MakeMoveRoot(block[0], game_wtm, move);
  2178.       else
  2179.         break;
  2180.     }
  2181.     game_wtm = Flip(game_wtm);
  2182.   }
  2183. }
  2184.  
  2185. /*
  2186.  *******************************************************************************
  2187.  *                                                                             *
  2188.  *   Kibitz() is used to whisper/kibitz information to a chess server.  It has *
  2189.  *   to handle the xboard whisper/kibitz interface.                            *
  2190.  *                                                                             *
  2191.  *******************************************************************************
  2192.  */
  2193. void Kibitz(int level, int wtm, int depth, int time, int value,
  2194.     uint64_t nodes, int ip, int tb_hits, char *pv) {
  2195.   int nps;
  2196.  
  2197.   nps = (int) ((time) ? 100 * nodes / (uint64_t) time : nodes);
  2198.   if (!puzzling) {
  2199.     char prefix[128];
  2200.  
  2201.     if (!(kibitz & 16))
  2202.       sprintf(prefix, "kibitz");
  2203.     else
  2204.       sprintf(prefix, "whisper");
  2205.     switch (level) {
  2206.       case 1:
  2207.         if ((kibitz & 15) >= 1) {
  2208.           if (value > 0)
  2209.             printf("%s mate in %d moves.\n\n", prefix, value);
  2210.           if (value < 0)
  2211.             printf("%s mated in %d moves.\n\n", prefix, -value);
  2212.         }
  2213.         break;
  2214.       case 2:
  2215.         if ((kibitz & 15) >= 2) {
  2216.           printf("%s ply=%d; eval=%s; nps=%s; time=%s(%d%%)", prefix, depth,
  2217.               DisplayEvaluationKibitz(value, wtm), DisplayKMB(nps, 0),
  2218.               DisplayTimeKibitz(time), ip);
  2219.           printf("; egtb=%s\n", DisplayKMB(tb_hits, 0));
  2220.         }
  2221.         break;
  2222.       case 3:
  2223.         if ((kibitz & 15) >= 3 && (nodes > 5000 || level == 2))
  2224.           printf("%s %s\n", prefix, pv);
  2225.         break;
  2226.       case 4:
  2227.         if ((kibitz & 15) >= 4)
  2228.           printf("%s %s\n", prefix, pv);
  2229.         break;
  2230.       case 5:
  2231.         if ((kibitz & 15) >= 5 && nodes > 5000) {
  2232.           printf("%s d%d-> %s/s %s(%d%%) %s %s ", prefix, depth,
  2233.               DisplayKMB(nps, 0), DisplayTimeKibitz(time), ip,
  2234.               DisplayEvaluationKibitz(value, wtm), pv);
  2235.           if (tb_hits)
  2236.             printf("egtb=%s", DisplayKMB(tb_hits, 0));
  2237.           printf("\n");
  2238.         }
  2239.         break;
  2240.     }
  2241.     value = (wtm) ? value : -value;
  2242.     if (post && level > 1) {
  2243.       if (strstr(pv, "book"))
  2244.         printf("      %2d  %5d %7d %" PRIu64 " %s\n", depth, value, time,
  2245.             nodes, pv + 10);
  2246.       else
  2247.         printf("      %2d  %5d %7d %" PRIu64 " %s\n", depth, value, time,
  2248.             nodes, pv);
  2249.     }
  2250.     fflush(stdout);
  2251.   }
  2252. }
  2253.  
  2254. /*
  2255.  *******************************************************************************
  2256.  *                                                                             *
  2257.  *   Output() is used to print the principal variation whenever it changes.    *
  2258.  *                                                                             *
  2259.  *******************************************************************************
  2260.  */
  2261. void Output(TREE * RESTRICT tree) {
  2262.   int wtm, i;
  2263.  
  2264. /*
  2265.  ************************************************************
  2266.  *                                                          *
  2267.  *  Output the PV by walking down the path being backed up. *
  2268.  *  We do set the "age" for this move to "4" which will     *
  2269.  *  keep it in the group of "search with all threads" moves *
  2270.  *  so that it will be searched faster.                     *
  2271.  *                                                          *
  2272.  ************************************************************
  2273.  */
  2274.   wtm = root_wtm;
  2275.   if (!abort_search) {
  2276.     kibitz_depth = iteration;
  2277.     end_time = ReadClock();
  2278.     DisplayPV(tree, 6, wtm, end_time - start_time, &tree->pv[1], 0);
  2279.     for (i = 0; i < n_root_moves; i++)
  2280.       if (tree->pv[1].path[1] == root_moves[i].move)
  2281.         break;
  2282.     root_moves[i].path = tree->pv[1];
  2283.     root_moves[i].bm_age = 4;
  2284.   }
  2285. }
  2286.  
  2287. /*
  2288.  *******************************************************************************
  2289.  *                                                                             *
  2290.  *   Trace() is used to print the search trace output each time a node is      *
  2291.  *   traversed in the tree.                                                    *
  2292.  *                                                                             *
  2293.  *******************************************************************************
  2294.  */
  2295. void Trace(TREE * RESTRICT tree, int ply, int depth, int wtm, int alpha,
  2296.     int beta, const char *name, int mode, int phase, int order) {
  2297.   int i;
  2298.  
  2299.   Lock(lock_io);
  2300.   for (i = 1; i < ply; i++)
  2301.     Print(-1, "  ");
  2302.   if (phase != EVALUATION) {
  2303.     Print(-1, "%d  %s(%d) d:%2d [%s,", ply, OutputMove(tree, ply, wtm,
  2304.             tree->curmv[ply]), order, depth, DisplayEvaluation(alpha, 1));
  2305.     Print(-1, "%s] n:%" PRIu64 " %s(%c:%d)", DisplayEvaluation(beta, 1),
  2306.         tree->nodes_searched, name, (mode) ? 'P' : 'S', phase);
  2307.     Print(-1, " (t=%d)\n", tree->thread_id);
  2308.   } else {
  2309.     Print(-1, "%d window/eval(%s) = {", ply, name);
  2310.     Print(-1, "%s, ", DisplayEvaluation(alpha, 1));
  2311.     Print(-1, "%s, ", DisplayEvaluation(depth, 1));
  2312.     Print(-1, "%s}\n", DisplayEvaluation(beta, 1));
  2313.   }
  2314.   fflush(0);
  2315.   Unlock(lock_io);
  2316. }
  2317.  
  2318. /*
  2319.  *******************************************************************************
  2320.  *                                                                             *
  2321.  *   StrCnt() counts the number of times a character occurs in a string.       *
  2322.  *                                                                             *
  2323.  *******************************************************************************
  2324.  */
  2325. int StrCnt(char *string, char testchar) {
  2326.    int count = 0; size_t i; // Pierre-Marie Baty -- fixed type
  2327.  
  2328.   for (i = 0; i < strlen(string); i++)
  2329.     if (string[i] == testchar)
  2330.       count++;
  2331.   return count;
  2332. }
  2333.  
  2334. /*
  2335.  *******************************************************************************
  2336.  *                                                                             *
  2337.  *   ValidMove() is used to verify that a move is playable.  It is mainly      *
  2338.  *   used to confirm that a move retrieved from the transposition/refutation   *
  2339.  *   and/or killer move is valid in the current position by checking the move  *
  2340.  *   against the current chess board, castling status, en passant status, etc. *
  2341.  *                                                                             *
  2342.  *******************************************************************************
  2343.  */
  2344. int ValidMove(TREE * RESTRICT tree, int ply, int wtm, int move) {
  2345.   int btm = Flip(wtm);
  2346.  
  2347. /*
  2348.  ************************************************************
  2349.  *                                                          *
  2350.  *  Make sure that the piece on <from> is the right color.  *
  2351.  *                                                          *
  2352.  ************************************************************
  2353.  */
  2354.   if (PcOnSq(From(move)) != ((wtm) ? Piece(move) : -Piece(move)))
  2355.     return 0;
  2356.   switch (Piece(move)) {
  2357. /*
  2358.  ************************************************************
  2359.  *                                                          *
  2360.  *  Null-moves are caught as it is possible for a killer    *
  2361.  *  move entry to be zero at certain times.                 *
  2362.  *                                                          *
  2363.  ************************************************************
  2364.  */
  2365.     case empty:
  2366.       return 0;
  2367. /*
  2368.  ************************************************************
  2369.  *                                                          *
  2370.  *  King moves are validated here if the king is moving two *
  2371.  *  squares at one time (castling moves).  Otherwise fall   *
  2372.  *  into the normal piece validation routine below.  For    *
  2373.  *  castling moves, we need to verify that the castling     *
  2374.  *  status is correct to avoid "creating" a new rook or     *
  2375.  *  king.                                                   *
  2376.  *                                                          *
  2377.  ************************************************************
  2378.  */
  2379.     case king:
  2380.       if (Abs(From(move) - To(move)) == 2) {
  2381.         if (Castle(ply, wtm) > 0) {
  2382.           if (To(move) == csq[wtm]) {
  2383.             if ((!(Castle(ply, wtm) & 2)) || (OccupiedSquares & OOO[wtm])
  2384.                 || (AttacksTo(tree, csq[wtm]) & Occupied(btm))
  2385.                 || (AttacksTo(tree, dsq[wtm]) & Occupied(btm))
  2386.                 || (AttacksTo(tree, esq[wtm]) & Occupied(btm)))
  2387.               return 0;
  2388.           } else if (To(move) == gsq[wtm]) {
  2389.             if ((!(Castle(ply, wtm) & 1)) || (OccupiedSquares & OO[wtm])
  2390.                 || (AttacksTo(tree, esq[wtm]) & Occupied(btm))
  2391.                 || (AttacksTo(tree, fsq[wtm]) & Occupied(btm))
  2392.                 || (AttacksTo(tree, gsq[wtm]) & Occupied(btm)))
  2393.               return 0;
  2394.           }
  2395.         } else
  2396.           return 0;
  2397.         return 1;
  2398.       }
  2399.       break;
  2400. /*
  2401.  ************************************************************
  2402.  *                                                          *
  2403.  *  Check for a normal pawn advance.                        *
  2404.  *                                                          *
  2405.  ************************************************************
  2406.  */
  2407.     case pawn:
  2408.       if (((wtm) ? To(move) - From(move) : From(move) - To(move)) < 0)
  2409.         return 0;
  2410.       if (Abs(From(move) - To(move)) == 8)
  2411.         return PcOnSq(To(move)) ? 0 : 1;
  2412.       if (Abs(From(move) - To(move)) == 16)
  2413.         return (PcOnSq(To(move)) || PcOnSq(To(move) + epdir[wtm])) ? 0 : 1;
  2414.       if (!Captured(move))
  2415.         return 0;
  2416. /*
  2417.  ************************************************************
  2418.  *                                                          *
  2419.  *  Check for an en passant capture which is somewhat       *
  2420.  *  unusual in that the [to] square does not contain the    *
  2421.  *  pawn being captured.  Make sure that the pawn being     *
  2422.  *  captured advanced two ranks the previous move.          *
  2423.  *                                                          *
  2424.  ************************************************************
  2425.  */
  2426.       if ((PcOnSq(To(move)) == 0)
  2427.           && (PcOnSq(To(move) + epdir[wtm]) == ((wtm) ? -pawn : pawn))
  2428.           && (EnPassantTarget(ply) & SetMask(To(move))))
  2429.         return 1;
  2430.       break;
  2431. /*
  2432.  ************************************************************
  2433.  *                                                          *
  2434.  *  Normal moves are all checked the same way.              *
  2435.  *                                                          *
  2436.  ************************************************************
  2437.  */
  2438.     case queen:
  2439.     case rook:
  2440.     case bishop:
  2441.       if (Attack(From(move), To(move)))
  2442.         break;
  2443.       return 0;
  2444.     case knight:
  2445.       break;
  2446.   }
  2447. /*
  2448.  ************************************************************
  2449.  *                                                          *
  2450.  *  All normal moves are validated in the same manner, by   *
  2451.  *  checking the from and to squares and also the attack    *
  2452.  *  status for completeness.                                *
  2453.  *                                                          *
  2454.  ************************************************************
  2455.  */
  2456.   return ((Captured(move) == ((wtm) ? -PcOnSq(To(move)) : PcOnSq(To(move))))
  2457.       && Captured(move) != king) ? 1 : 0;
  2458. }
  2459.  
  2460. /* last modified 02/26/14 */
  2461. /*
  2462.  *******************************************************************************
  2463.  *                                                                             *
  2464.  *   VerifyMove() tests a move to confirm it is absolutely legal. It shouldn't *
  2465.  *   be used inside the search, but can be used to check a 21-bit (compressed) *
  2466.  *   move to be sure it is safe to make it on the permanent game board.        *
  2467.  *                                                                             *
  2468.  *******************************************************************************
  2469.  */
  2470. int VerifyMove(TREE * RESTRICT tree, int ply, int wtm, int move) {
  2471.   unsigned moves[256], *mv, *mvp;
  2472.  
  2473. /*
  2474.  Generate moves, then eliminate any that are illegal.
  2475.  */
  2476.   if (move == 0)
  2477.     return 0;
  2478.   tree->status[MAXPLY] = tree->status[ply];
  2479.   mvp = GenerateCaptures(tree, MAXPLY, wtm, moves);
  2480.   mvp = GenerateNoncaptures(tree, MAXPLY, wtm, mvp);
  2481.   for (mv = &moves[0]; mv < mvp; mv++) {
  2482.     MakeMove(tree, MAXPLY, wtm, *mv);
  2483.     if (!Check(wtm) && move == *mv) {
  2484.       UnmakeMove(tree, MAXPLY, wtm, *mv);
  2485.       return 1;
  2486.     }
  2487.     UnmakeMove(tree, MAXPLY, wtm, *mv);
  2488.   }
  2489.   return 0;
  2490. }
  2491.  
  2492. /*
  2493.  *******************************************************************************
  2494.  *                                                                             *
  2495.  *   Windows NUMA support                                                      *
  2496.  *                                                                             *
  2497.  *******************************************************************************
  2498.  */
  2499. #if !defined(UNIX)
  2500. static BOOL(WINAPI * pGetNumaHighestNodeNumber) (PULONG);
  2501. static BOOL(WINAPI * pGetNumaNodeProcessorMask) (UCHAR, PULONGLONG);
  2502. static DWORD(WINAPI * pSetThreadIdealProcessor) (HANDLE, DWORD);
  2503. static volatile BOOL fThreadsInitialized = FALSE;
  2504. static BOOL fSystemIsNUMA = FALSE;
  2505. static ULONGLONG ullProcessorMask[256];
  2506. static ULONG ulNumaNodes;
  2507. static ULONG ulNumaNode = 0;
  2508.  
  2509. // Get NUMA-related information from Windows
  2510. static void WinNumaInit(void) {
  2511.   HMODULE hModule;
  2512.   ULONG ulCPU, ulNode;
  2513.   ULONGLONG ullMask;
  2514.   DWORD dwCPU;
  2515.  
  2516.   if (!fThreadsInitialized) {
  2517.     Lock(lock_smp);
  2518.     if (!fThreadsInitialized) {
  2519.       printf("\nInitializing multiple threads.\n");
  2520.       fThreadsInitialized = TRUE;
  2521.       hModule = GetModuleHandle("kernel32");
  2522.       pGetNumaHighestNodeNumber =
  2523.           (void *) GetProcAddress(hModule, "GetNumaHighestNodeNumber");
  2524.       pGetNumaNodeProcessorMask =
  2525.           (void *) GetProcAddress(hModule, "GetNumaNodeProcessorMask");
  2526.       pSetThreadIdealProcessor =
  2527.           (void *) GetProcAddress(hModule, "SetThreadIdealProcessor");
  2528.       if (pGetNumaHighestNodeNumber && pGetNumaNodeProcessorMask &&
  2529.           pGetNumaHighestNodeNumber(&ulNumaNodes) && (ulNumaNodes > 0)) {
  2530.         fSystemIsNUMA = TRUE;
  2531.         if (ulNumaNodes > 255)
  2532.           ulNumaNodes = 255;
  2533.         printf("System is NUMA. %" PRId64 " nodes reported by Windows\n", // Pierre-Marie Baty -- fixed format string
  2534.             (int64_t) (ulNumaNodes + 1)); // Pierre-Marie Baty -- added type cast
  2535.         for (ulNode = 0; ulNode <= ulNumaNodes; ulNode++) {
  2536.           pGetNumaNodeProcessorMask((UCHAR) ulNode,
  2537.               &ullProcessorMask[ulNode]);
  2538.           printf("Node %" PRId64 " CPUs: ", (int64_t) ulNode); // Pierre-Marie Baty -- fixed format string + added type cast
  2539.           ullMask = ullProcessorMask[ulNode];
  2540.           if (0 == ullMask)
  2541.             fSystemIsNUMA = FALSE;
  2542.           else {
  2543.             ulCPU = 0;
  2544.             do {
  2545.               if (ullMask & 1)
  2546.                 printf("%" PRId64 " ", (int64_t) ulCPU); // Pierre-Marie Baty -- fixed format string + added type cast
  2547.               ulCPU++;
  2548.               ullMask >>= 1;
  2549.             } while (ullMask);
  2550.           }
  2551.           printf("\n");
  2552.         }
  2553. // Thread 0 was already started on some CPU. To simplify things further,
  2554. // exchange ProcessorMask[0] and ProcessorMask[node for that CPU],
  2555. // so ProcessorMask[0] would always be node for thread 0
  2556.         dwCPU =
  2557.             pSetThreadIdealProcessor(GetCurrentThread(), MAXIMUM_PROCESSORS);
  2558.         printf("Current ideal CPU is %llu\n", (long long unsigned) dwCPU); // Pierre-Marie Baty -- added type cast
  2559.         pSetThreadIdealProcessor(GetCurrentThread(), dwCPU);
  2560.         if ((((DWORD) - 1) != dwCPU) && (MAXIMUM_PROCESSORS != dwCPU)
  2561.             && !(ullProcessorMask[0] & (1uLL << dwCPU))) { // Pierre-Marie Baty -- fixed type
  2562.           for (ulNode = 1; ulNode <= ulNumaNodes; ulNode++) {
  2563.             if (ullProcessorMask[ulNode] & (1uLL << dwCPU)) { // Pierre-Marie Baty -- fixed type
  2564.               printf("Exchanging nodes 0 and %" PRId64 "\n", (int64_t) ulNode); // Pierre-Marie Baty -- fixed format string + added type cast
  2565.               ullMask = ullProcessorMask[ulNode];
  2566.               ullProcessorMask[ulNode] = ullProcessorMask[0];
  2567.               ullProcessorMask[0] = ullMask;
  2568.               break;
  2569.             }
  2570.           }
  2571.         }
  2572.       } else
  2573.         printf("System is SMP, not NUMA.\n");
  2574.     }
  2575.     Unlock(lock_smp);
  2576.   }
  2577. }
  2578.  
  2579. // Start thread. For NUMA system set its affinity.
  2580. #  if (CPUS > 1)
  2581. pthread_t NumaStartThread(void *func, void *args) {
  2582.   HANDLE hThread;
  2583.   ULONGLONG ullMask;
  2584.  
  2585.   WinNumaInit();
  2586.   if (fSystemIsNUMA) {
  2587.     ulNumaNode++;
  2588.     if (ulNumaNode > ulNumaNodes)
  2589.       ulNumaNode = 0;
  2590.     ullMask = ullProcessorMask[ulNumaNode];
  2591.     printf("Starting thread on node %" PRId64 " CPU mask %I64d\n", (int64_t) ulNumaNode, // Pierre-Marie Baty -- fixed format string + added type cast
  2592.         ullMask);
  2593.     SetThreadAffinityMask(GetCurrentThread(), (DWORD_PTR) ullMask);
  2594.     hThread = (HANDLE) _beginthreadex(0, 0, func, args, CREATE_SUSPENDED, 0);
  2595.     SetThreadAffinityMask(hThread, (DWORD_PTR) ullMask);
  2596.     ResumeThread(hThread);
  2597.     SetThreadAffinityMask(GetCurrentThread(), (DWORD_PTR) ullProcessorMask[0]); // Pierre-Marie Baty -- added type cast
  2598.   } else
  2599.     hThread = (HANDLE) _beginthreadex(0, 0, func, args, 0, 0);
  2600.   return hThread;
  2601. }
  2602. #  endif
  2603.  
  2604. // Allocate memory for thread #N
  2605. void *WinMalloc(size_t cbBytes, int iThread) {
  2606.   HANDLE hThread;
  2607.   DWORD_PTR dwAffinityMask;
  2608.   void *pBytes;
  2609.   ULONG ulNode;
  2610.  
  2611.   WinNumaInit();
  2612.   if (fSystemIsNUMA) {
  2613.     ulNode = iThread % (ulNumaNodes + 1);
  2614.     hThread = GetCurrentThread();
  2615.     dwAffinityMask = SetThreadAffinityMask(hThread, (DWORD_PTR) ullProcessorMask[ulNode]); // Pierre-Marie Baty -- added type cast
  2616.     pBytes = VirtualAlloc(NULL, cbBytes, MEM_COMMIT, PAGE_READWRITE);
  2617.     if (pBytes == NULL)
  2618.       ExitProcess(GetLastError());
  2619.     memset(pBytes, 0, cbBytes);
  2620.     SetThreadAffinityMask(hThread, dwAffinityMask);
  2621.   } else {
  2622.     pBytes = VirtualAlloc(NULL, cbBytes, MEM_COMMIT, PAGE_READWRITE);
  2623.     if (pBytes == NULL)
  2624.       ExitProcess(GetLastError());
  2625.     memset(pBytes, 0, cbBytes);
  2626.   }
  2627.   return pBytes;
  2628. }
  2629.  
  2630. // Allocate interleaved memory
  2631. void *WinMallocInterleaved(size_t cbBytes, int cThreads) {
  2632.   char *pBase;
  2633.   char *pEnd;
  2634.   char *pch;
  2635.   HANDLE hThread;
  2636.   DWORD_PTR dwAffinityMask;
  2637.   ULONG ulNode;
  2638.   SYSTEM_INFO sSysInfo;
  2639.   size_t dwStep;
  2640.   int iThread;
  2641.   DWORD dwPageSize;             // the page size on this computer
  2642.   LPVOID lpvResult;
  2643.  
  2644.   WinNumaInit();
  2645.   if (fSystemIsNUMA && (cThreads > 1)) {
  2646.     GetSystemInfo(&sSysInfo); // populate the system information structure
  2647.     dwPageSize = sSysInfo.dwPageSize;
  2648. // Reserve pages in the process's virtual address space.
  2649.     pBase = (char *) VirtualAlloc(NULL, cbBytes, MEM_RESERVE, PAGE_NOACCESS);
  2650.     if (pBase == NULL) {
  2651.       printf("VirtualAlloc() reserve failed\n");
  2652.       CraftyExit(0);
  2653.     }
  2654. // Now walk through memory, committing each page
  2655.     hThread = GetCurrentThread();
  2656.     dwStep = dwPageSize * cThreads;
  2657.     pEnd = pBase + cbBytes;
  2658.     for (iThread = 0; iThread < cThreads; iThread++) {
  2659.       ulNode = iThread % (ulNumaNodes + 1);
  2660.       dwAffinityMask =
  2661.           SetThreadAffinityMask(hThread, (DWORD_PTR) ullProcessorMask[ulNode]); // Pierre-Marie Baty -- added type cast
  2662.       for (pch = pBase + iThread * dwPageSize; pch < pEnd; pch += dwStep) {
  2663.         lpvResult = VirtualAlloc(pch, // next page to commit
  2664.             dwPageSize, // page size, in bytes
  2665.             MEM_COMMIT, // allocate a committed page
  2666.             PAGE_READWRITE); // read/write access
  2667.         if (lpvResult == NULL)
  2668.           ExitProcess(GetLastError());
  2669.         memset(lpvResult, 0, dwPageSize);
  2670.       }
  2671.       SetThreadAffinityMask(hThread, dwAffinityMask);
  2672.     }
  2673.   } else {
  2674.     pBase = VirtualAlloc(NULL, cbBytes, MEM_COMMIT, PAGE_READWRITE);
  2675.     if (pBase == NULL)
  2676.       ExitProcess(GetLastError());
  2677.     memset(pBase, 0, cbBytes);
  2678.   }
  2679.   return (void *) pBase;
  2680. }
  2681.  
  2682. // Free interleaved memory
  2683. void WinFreeInterleaved(void *pMemory, size_t cBytes) {
  2684.   VirtualFree(pMemory, 0, MEM_RELEASE);
  2685. }
  2686. #endif
  2687.