Subversion Repositories Games.Chess Giants

Rev

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

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