Subversion Repositories Games.Chess Giants

Rev

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

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