#include <stdarg.h>
 
#include <errno.h>
 
#include <ctype.h>
 
#include "chess.h"
 
#include "data.h"
 
#if defined(UNIX)
 
#  include <unistd.h>
 
#  include <sys/types.h>
 
#  include <signal.h>
 
#  include <sys/wait.h>
 
#  include <sys/times.h>
 
#  include <sys/time.h>
 
#else
 
#  include <windows.h>
 
#  include <winbase.h>
 
#  include <wincon.h>
 
#  include <io.h>
 
#  include <time.h>
 
#endif
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   AlignedMalloc() is used to allocate memory on a precise boundary,         *
 
 *   primarily to optimize cache performance by forcing the start of the       *
 
 *   memory region being allocated to match up so that a structure will lie    *
 
 *   on a single cache line rather than being split across two, assuming the   *
 
 *   structure is 64 bytes or less of course.                                  *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
void AlignedMalloc(void **pointer, int alignment, size_t size) {
 
  segments
[nsegments
][0] = malloc(size 
+ alignment 
- 1); 
  segments[nsegments][1] =
 
      (void *) (((uintptr_t) segments[nsegments][0] + alignment -
 
          1) & ~(alignment - 1));
 
  *pointer = segments[nsegments][1];
 
  nsegments++;
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   atoiKMB() is used to read in an integer value that can have a "K" or "M"  *
 
 *   appended to it to multiply by 1024 or 1024*1024.  It returns a 64 bit     *
 
 *   value since memory sizes can exceed 4gb on modern hardware.               *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
uint64_t atoiKMB(char *input) {
 
  uint64_t size;
 
 
 
    size *= 1 << 10;
 
    size *= 1 << 20;
 
    size *= 1 << 30;
 
  return size;
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   AlignedRemalloc() is used to change the size of a memory block that has   *
 
 *   previously been allocated using AlignedMalloc().                          *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
void AlignedRemalloc(void **pointer, int alignment, size_t size) {
 
  int i;
 
 
 
  for (i = 0; i < nsegments; i++)
 
    if (segments[i][1] == *pointer)
 
      break;
 
  if (i == nsegments) {
 
    Print(4095, "ERROR  AlignedRemalloc() given an invalid pointer\n");
 
  }
 
  segments
[i
][0] = malloc(size 
+ alignment 
- 1); 
  segments[i][1] =
 
      (void *) (((uintptr_t) segments[i][0] + alignment - 1) & ~(alignment -
 
          1));
 
  *pointer = segments[i][1];
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   BookClusterIn() is used to read a cluster in as characters, then stuff    *
 
 *   the data into a normal array of structures that can be used within Crafty *
 
 *   without any endian issues.                                                *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
void BookClusterIn(FILE * file, int positions, BOOK_POSITION * buffer) {
 
  int i;
 
  char file_buffer[BOOK_CLUSTER_SIZE * sizeof(BOOK_POSITION)];
 
 
 
  i 
= fread(file_buffer
, positions
, sizeof(BOOK_POSITION
), file
); 
  if (i <= 0)
 
    perror("BookClusterIn fread error: ");  
  for (i = 0; i < positions; i++) {
 
    buffer[i].position =
 
        BookIn64((unsigned char *) (file_buffer + i * sizeof(BOOK_POSITION)));
 
    buffer[i].status_played =
 
        BookIn32((unsigned char *) (file_buffer + i * sizeof(BOOK_POSITION) +
 
            8));
 
    buffer[i].learn =
 
        BookIn32f((unsigned char *) (file_buffer + i * sizeof(BOOK_POSITION) +
 
            12));
 
  }
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   BookClusterOut() is used to write a cluster out as characters, after      *
 
 *   converting the normal array of structures into character data that is     *
 
 *   Endian-independent.                                                       *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
void BookClusterOut(FILE * file, int positions, BOOK_POSITION * buffer) {
 
  int i;
 
  char file_buffer[BOOK_CLUSTER_SIZE * sizeof(BOOK_POSITION)];
 
 
 
  for (i = 0; i < positions; i++) {
 
    memcpy(file_buffer 
+ i 
* sizeof(BOOK_POSITION
),  
        BookOut64(buffer[i].position), 8);
 
    memcpy(file_buffer 
+ i 
* sizeof(BOOK_POSITION
) + 8,  
        BookOut32(buffer[i].status_played), 4);
 
    memcpy(file_buffer 
+ i 
* sizeof(BOOK_POSITION
) + 12,  
        BookOut32f(buffer[i].learn), 4);
 
  }
 
  fwrite(file_buffer
, positions
, sizeof(BOOK_POSITION
), file
);  
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   BookIn32f() is used to convert 4 bytes from the book file into a valid 32 *
 
 *   bit binary value.  This eliminates endian worries that make the binary    *
 
 *   book non-portable across many architectures.                              *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
float BookIn32f(unsigned char *ch) {
 
  union {
 
    float fv;
 
    int iv;
 
  } temp;
 
 
 
  temp.iv = ch[3] << 24 | ch[2] << 16 | ch[1] << 8 | ch[0];
 
  return temp.fv;
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   BookIn32() is used to convert 4 bytes from the book file into a valid 32  *
 
 *   bit binary value.  this eliminates endian worries that make the  binary   *
 
 *   book non-portable across many architectures.                              *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
int BookIn32(unsigned char *ch) {
 
  return ch[3] << 24 | ch[2] << 16 | ch[1] << 8 | ch[0];
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   BookIn64() is used to convert 8 bytes from the book file into a valid 64  *
 
 *   bit binary value.  this eliminates endian worries that make the  binary   *
 
 *   book non-portable across many architectures.                              *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
uint64_t BookIn64(unsigned char *ch) {
 
  return (uint64_t) ch[7] << 56 | (uint64_t) ch[6] << 48 | (uint64_t)
 
      ch[5] << 40 | (uint64_t) ch[4] << 32 | (uint64_t) ch[3]
 
      << 24 | (uint64_t) ch[2] << 16 | (uint64_t) ch[1] << 8 | (uint64_t)
 
      ch[0];
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   BookOut32() is used to convert 4 bytes from a valid 32 bit binary value   *
 
 *   to a book value.  this eliminates endian worries that make the  binary    *
 
 *   book non-portable across many architectures.                              *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
unsigned char *BookOut32(int val) {
 
  convert_buff[3] = val >> 24 & 0xff;
 
  convert_buff[2] = val >> 16 & 0xff;
 
  convert_buff[1] = val >> 8 & 0xff;
 
  convert_buff[0] = val & 0xff;
 
  return convert_buff;
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   BookOut32f() is used to convert 4 bytes from a valid 32 bit binary value  *
 
 *   to a book value.  this eliminates endian worries that make the  binary    *
 
 *   book non-portable across many architectures.                              *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
unsigned char *BookOut32f(float val) {
 
  union {
 
    float fv;
 
    int iv;
 
  } temp;
 
 
 
  temp.fv = val;
 
  convert_buff[3] = temp.iv >> 24 & 0xff;
 
  convert_buff[2] = temp.iv >> 16 & 0xff;
 
  convert_buff[1] = temp.iv >> 8 & 0xff;
 
  convert_buff[0] = temp.iv & 0xff;
 
  return convert_buff;
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   BookOut64() is used to convert 8 bytes from a valid 64 bit binary value   *
 
 *   to a book value.  this eliminates endian worries that make the  binary    *
 
 *   book non-portable across many architectures.                              *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
unsigned char *BookOut64(uint64_t val) {
 
  convert_buff[7] = val >> 56 & 0xff;
 
  convert_buff[6] = val >> 48 & 0xff;
 
  convert_buff[5] = val >> 40 & 0xff;
 
  convert_buff[4] = val >> 32 & 0xff;
 
  convert_buff[3] = val >> 24 & 0xff;
 
  convert_buff[2] = val >> 16 & 0xff;
 
  convert_buff[1] = val >> 8 & 0xff;
 
  convert_buff[0] = val & 0xff;
 
  return convert_buff;
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   the following functions are used to determine if keyboard input is        *
 
 *   present.  there are several ways this is done depending on which          *
 
 *   operating system is used.  The primary function name is CheckInput() but  *
 
 *   for simplicity there are several O/S-specific versions.                   *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
#if !defined(UNIX)
 
#  include <windows.h>
 
#  include <conio.h>
 
/* Windows NT using PeekNamedPipe() function */
 
int CheckInput(void) {
 
  int i;
 
  static int init = 0, pipe;
 
  static HANDLE inh;
 
  DWORD dw;
 
 
 
  if (!xboard && !_isatty(_fileno(stdin))) // Pierre-Marie Baty -- ISO C++ names fix
 
    return 0;
 
  if (batch_mode)
 
    return 0;
 
    return 1;
 
  if (xboard) {
 
#  if defined(FILE_CNT)
 
    if (stdin->_cnt > 0)
 
      return stdin->_cnt;
 
#  endif
 
    if (!init) {
 
      init = 1;
 
      inh = GetStdHandle(STD_INPUT_HANDLE);
 
      pipe = !GetConsoleMode(inh, &dw);
 
      if (!pipe) {
 
        SetConsoleMode(inh, dw & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT));
 
        FlushConsoleInputBuffer(inh);
 
      }
 
    }
 
    if (pipe) {
 
      if (!PeekNamedPipe(inh, NULL, 0, NULL, &dw, NULL)) {
 
        return 1;
 
      }
 
      return dw;
 
    } else {
 
      GetNumberOfConsoleInputEvents(inh, &dw);
 
      return dw <= 1 ? 0 : dw;
 
    }
 
  } else {
 
    i = _kbhit();
 
  }
 
  return i;
 
}
 
#endif
 
#if defined(UNIX)
 
/* Simple UNIX approach using select with a zero timeout value */
 
int CheckInput(void) {
 
  fd_set readfds;
 
  struct timeval tv;
 
  int data;
 
 
 
  if (!xboard && !isatty(fileno(stdin)))
 
    return 0;
 
  if (batch_mode)
 
    return 0;
 
    return 1;
 
  FD_ZERO(&readfds);
 
  FD_SET(fileno(stdin), &readfds);
 
  tv.tv_sec = 0;
 
  tv.tv_usec = 0;
 
  select(16, &readfds, 0, 0, &tv);
 
  data = FD_ISSET(fileno(stdin), &readfds);
 
  return data;
 
}
 
#endif
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   ClearHashTableScores() is used to clear hash table scores without         *
 
 *   clearing the best move, so that move ordering information is preserved.   *
 
 *   We clear the scorew as we approach a 50 move rule so that hash scores     *
 
 *   won't give us false scores since the hash signature does not include any  *
 
 *   search path information in it.                                            *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
void ClearHashTableScores(void) {
 
  int i;
 
 
 
  if (hash_table)
 
    for (i = 0; i < (int)hash_table_size; i++) { // Pierre-Marie Baty -- added type cast
 
      (hash_table + i)->word2 ^= (hash_table + i)->word1;
 
      (hash_table + i)->word1 =
 
          ((hash_table + i)->word1 & mask_clear_entry) | (uint64_t) 65536;
 
      (hash_table + i)->word2 ^= (hash_table + i)->word1;
 
    }
 
}
 
 
 
/* last modified 02/28/14 */
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   ComputeDifficulty() is used to compute the difficulty rating for the      *
 
 *   current position, which really is based on nothing more than how many     *
 
 *   times we changed our mind in an iteration.  No changes caused the         *
 
 *   difficulty to drop (easier, use less time), while more changes ramps the  *
 
 *   difficulty up (harder, use more time).  It is called at the end of an     *
 
 *   iteration as well as when displaying fail-high/fail-low moves, in an      *
 
 *   effort to give the operator a heads-up on how long we are going to be     *
 
 *   stuck in an active search.                                                *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
int ComputeDifficulty(int difficulty, int direction) {
 
  int searched = 0, i;
 
 
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Step 1.  Handle fail-high-fail low conditions, which    *
 
 *  occur in the middle of an iteration.  The actions taken *
 
 *  are as follows:                                         *
 
 *                                                          *
 
 *  (1) Determine how many moves we have searched first, as *
 
 *  this is important.  If we have not searched anything    *
 
 *  (which means we failed high on the first move at the    *
 
 *  root, at the beginning of a new iteration), a fail low  *
 
 *  will immediately set difficult back to 100% (if it is   *
 
 *  currently below 100%).  A fail high on the first move   *
 
 *  will not change difficulty at all.  Successive fail     *
 
 *  highs or fail lows will not change difficulty, we will  *
 
 *  not even get into this code on the repeats.             *
 
 *                                                          *
 
 *  (2) If we are beyond the first move, then this must be  *
 
 *  a fail high condition.  Since we are changing our mind, *
 
 *  we need to increase the difficulty level to expend more *
 
 *  time on this iteration.  If difficulty is currently     *
 
 *  less than 100%, we set it to 120%.  If it is currently  *
 
 *  at 100% or more, we simply add 20% to the value and     *
 
 *  continue searching, but with a longer time constraint.  *
 
 *  Each time we fail high, we are changing our mind, and   *
 
 *  we will increase difficulty by another 20%.             *
 
 *                                                          *
 
 *  (3) Direction = 0 means we are at the end of an the     *
 
 *  iteration.  Here we simply note if we changed our mind  *
 
 *  during this iteration.  If not, we reduce difficulty    *
 
 *  to 90% of its previous value.                           *
 
 *                                                          *
 
 *  After any of these changes, we enforce a lower bound of *
 
 *  60% and an upperbound of 200% before we return.         *
 
 *                                                          *
 
 *  Note:  direction = +1 means we failed high on the move, *
 
 *  direction = -1 means we failed low on the move, and     *
 
 *  direction = 0 means we have completed the iteration and *
 
 *  all moves were searched successfully.                   *
 
 *                                                          *
 
 ************************************************************
 
 */
 
  if (direction) {
 
    for (i = 0; i < n_root_moves; i++)
 
      if (root_moves[i].status & 8)
 
        searched++;
 
    if (searched == 0) {
 
      if (direction > 0)
 
        return difficulty;
 
      if (direction < 0)
 
        difficulty = Max(100, difficulty);
 
    } else {
 
      if (difficulty < 100)
 
        difficulty = 120;
 
      else
 
        difficulty = difficulty + 20;
 
    }
 
  }
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Step 2.  We are at the end of an iteration.  If we did  *
 
 *  not change our mind and stuck with one move, we reduce  *
 
 *  difficulty by 10% since the move looks to be a little   *
 
 *  "easier" when we don't change our mind.                 *
 
 *                                                          *
 
 ************************************************************
 
 */
 
  else {
 
    searched = 0;
 
    for (i = 0; i < n_root_moves; i++)
 
      if (root_moves[i].bm_age == 3)
 
        searched++;
 
    if (searched <= 1)
 
      difficulty = 90 * difficulty / 100;
 
  }
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Step 4.  Apply limits.  We don't let difficulty go      *
 
 *  above 200% (take 2x the target time) nor do we let it   *
 
 *  drop below 60 (take .6x target time) to avoid moving    *
 
 *  too quickly and missing something tactically where the  *
 
 *  move initially looks obvious but really is not.         *
 
 *                                                          *
 
 ************************************************************
 
 */
 
  difficulty = Max(60, Min(difficulty, 200));
 
  return difficulty;
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   CraftyExit() is used to terminate the program.  the main functionality    *
 
 *   is to make sure the "quit" flag is set so that any spinning threads will  *
 
 *   also exit() rather than spinning forever which can cause GUIs to hang     *
 
 *   since all processes have not terminated.                                  *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
void CraftyExit(int exit_type) {
 
  int proc;
 
 
 
  for (proc = 1; proc < CPUS; proc++)
 
    thread[proc].terminate = 1;
 
  while (smp_threads);
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   DisplayArray() prints array data either 8 or 16 values per line, and also *
 
 *   reverses the output for arrays that overlay the chess board so that the   *
 
 *   'white side" is at the bottom rather than the top.  this is mainly used   *
 
 *   from inside Option() to display the many evaluation terms.                *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
void DisplayArray(int *array, int size) {
 
  int i, j, len = 16;
 
 
 
  if (Abs(size) % 10 == 0)
 
    len = 10;
 
  else if (Abs(size) % 8 == 0)
 
    len = 8;
 
  if (size > 0 && size % 16 == 0 && len == 8)
 
    len = 16;
 
  if (size > 0) {
 
    for (i = 0; i < size; i++) {
 
      if ((i + 1) % len == 0) {
 
        if (i < size - 1)
 
      }
 
    }
 
    if (i % len != 0)
 
  }
 
  if (size < 0) {
 
    for (i = 0; i < 8; i++) {
 
      for (j = 0; j < 8; j++) {
 
        printf("%3d ", array
[(7 - i
) * 8 + j
]);  
      }
 
    }
 
    printf("    ---------------------------------\n");  
  }
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   DisplayArray() prints array data either 8 or 16 values per line, and also *
 
 *   reverses the output for arrays that overlay the chess board so that the   *
 
 *   'white side" is at the bottom rather than the top.  this is mainly used   *
 
 *   from inside Option() to display the many evaluation terms.                *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
void DisplayArrayX2(int *array, int *array2, int size) {
 
  int i, j;
 
 
 
  if (size == 256) {
 
    printf("    ----------- Middlegame -----------   ");  
    printf("    ------------- Endgame -----------\n");  
    for (i = 0; i < 8; i++) {
 
      for (j = 0; j < 8; j++)
 
        printf("%3d ", array
[(7 - i
) * 8 + j
]);  
      for (j = 0; j < 8; j++)
 
        printf("%3d ", array2
[(7 - i
) * 8 + j
]);  
    }
 
        ("    ----------------------------------       ---------------------------------\n");
 
  } else if (size == 32) {
 
    printf("    ----------- Middlegame -----------   ");  
    printf("    ------------- Endgame -----------\n");  
    for (i = 0; i < 8; i++)
 
    for (i = 0; i < 8; i++)
 
  } else if (size <= 20) {
 
    size = size / 2;
 
    for (i = 0; i < size; i++)
 
    for (i = 0; i < size; i++)
 
  } else if (size > 128) {
 
    printf("    ----------- Middlegame -----------   ");  
    printf("    ------------- Endgame -----------\n");  
    for (i = 0; i < size / 32; i++) {
 
      for (j = 0; j < 8; j++)
 
        printf("%3d ", array
[(7 - i
) * 8 + j
]);  
      for (j = 0; j < 8; j++)
 
        printf("%3d ", array2
[(7 - i
) * 8 + j
]);  
    }
 
  } else
 
    Print(4095, "ERROR, invalid size = -%d in packet\n", size);
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   DisplayBitBoard() is a debugging function used to display bitboards in a  *
 
 *   more visual way.  they are displayed as an 8x8 matrix oriented as the     *
 
 *   normal chess board is, with a1 at the lower left corner.                  *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
void DisplayBitBoard(uint64_t board) {
 
  int i, j, x;
 
 
 
  for (i = 56; i >= 0; i -= 8) {
 
    x = (board >> i) & 255;
 
    for (j = 1; j < 256; j = j << 1)
 
      if (x & j)
 
        Print(4095, "X ");
 
      else
 
        Print(4095, "- ");
 
    Print(4095, "\n");
 
  }
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   Display2BitBoards() is a debugging function used to display bitboards in  *
 
 *   a more visual way.  they are displayed as an 8x8 matrix oriented as the   *
 
 *   normal chess board is, with a1 at the lower left corner.  this function   *
 
 *   displays 2 boards side by side for comparison.                            *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
void Display2BitBoards(uint64_t board1, uint64_t board2) {
 
  int i, j, x, y;
 
 
 
  for (i = 56; i >= 0; i -= 8) {
 
    x = (board1 >> i) & 255;
 
    for (j = 1; j < 256; j = j << 1)
 
      if (x & j)
 
      else
 
    y = (board2 >> i) & 255;
 
    for (j = 1; j < 256; j = j << 1)
 
      if (y & j)
 
      else
 
  }
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   DisplayChessBoard() is used to display the board since it is kept in      *
 
 *   both the bit-board and array formats, here we use the array format which  *
 
 *   is nearly ready for display as is.                                        *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
void DisplayChessBoard(FILE * display_file, POSITION pos) {
 
  int display_board[64], i, j;
 
  static const char display_string[16][4] =
 
      { "<K>", "<Q>", "<R>", "<B>", "<N>", "<P>", "   ",
 
    "-P-", "-N-", "-B-", "-R-", "-Q-", "-K-", " . "
 
  };
 
 
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  First, convert square values to indices to the proper   *
 
 *  text string.                                            *
 
 *                                                          *
 
 ************************************************************
 
 */
 
  for (i = 0; i < 64; i++) {
 
    display_board[i] = pos.board[i] + 6;
 
    if (pos.board[i] == 0) {
 
      if (((i / 8) & 1) == ((i % 8) & 1))
 
        display_board[i] = 13;
 
    }
 
  }
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Now that that's done, simply display using 8 squares    *
 
 *  per line.                                               *
 
 *                                                          *
 
 ************************************************************
 
 */
 
  fprintf(display_file
, "\n       +---+---+---+---+---+---+---+---+\n");  
  for (i = 7; i >= 0; i--) {
 
    fprintf(display_file
, "   %2d  ", i 
+ 1);  
    for (j = 0; j < 8; j++)
 
      fprintf(display_file
, "|%s", display_string
[display_board
[i 
* 8 + j
]]);  
    fprintf(display_file
, "       +---+---+---+---+---+---+---+---+\n");  
  }
 
  fprintf(display_file
, "         a   b   c   d   e   f   g   h\n\n");  
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   DisplayChessMove() is a debugging function that displays a chess move in  *
 
 *   a very simple (non-algebraic) form.                                       *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
void DisplayChessMove(char *title, int move) {
 
  Print(4095, "%s  piece=%d, from=%d, to=%d, captured=%d, promote=%d\n",
 
      title, Piece(move), From(move), To(move), Captured(move),
 
      Promote(move));
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   DisplayEvaluation() is used to convert the evaluation to a string that    *
 
 *   can be displayed.  The length is fixed so that screen formatting will     *
 
 *   look nice and aligned.                                                    *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
char *DisplayEvaluation(int value, int wtm) {
 
  int tvalue;
 
  static char out[10];
 
 
 
  tvalue = (wtm) ? value : -value;
 
  if (!MateScore(value))
 
    sprintf(out
, "%7.2f", ((float) tvalue
) / 100.0);  
  else if (Abs(value) > MATE) {
 
    if (tvalue < 0)
 
    else
 
  } else if (value == MATE - 2 && wtm)
 
  else if (value == MATE - 2 && !wtm)
 
  else if (value == -(MATE - 1) && wtm)
 
  else if (value == -(MATE - 1) && !wtm)
 
  else if (value > 0 && wtm)
 
    sprintf(out
, "  Mat%.2d", (MATE 
- value
) / 2);  
  else if (value > 0 && !wtm)
 
    sprintf(out
, " -Mat%.2d", (MATE 
- value
) / 2);  
  else if (wtm)
 
    sprintf(out
, " -Mat%.2d", (MATE 
- Abs
(value
)) / 2);  
  else
 
    sprintf(out
, "  Mat%.2d", (MATE 
- Abs
(value
)) / 2);  
  return out;
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   DisplayEvaluationKibitz() is used to convert the evaluation to a string   *
 
 *   that can be displayed.  The length is variable so that ICC kibitzes and   *
 
 *   whispers will look nicer.                                                 *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
char *DisplayEvaluationKibitz(int value, int wtm) {
 
  int tvalue;
 
  static char out[10];
 
 
 
  tvalue = (wtm) ? value : -value;
 
  if (!MateScore(value))
 
    sprintf(out
, "%+.2f", ((float) tvalue
) / 100.0);  
  else if (Abs(value) > MATE) {
 
    if (tvalue < 0)
 
    else
 
  } else if (value == MATE - 2 && wtm)
 
  else if (value == MATE - 2 && !wtm)
 
  else if (value == -(MATE - 1) && wtm)
 
  else if (value == -(MATE - 1) && !wtm)
 
  else if (value > 0 && wtm)
 
    sprintf(out
, "Mat%.2d", (MATE 
- value
) / 2);  
  else if (value > 0 && !wtm)
 
    sprintf(out
, "-Mat%.2d", (MATE 
- value
) / 2);  
  else if (wtm)
 
    sprintf(out
, "-Mat%.2d", (MATE 
- Abs
(value
)) / 2);  
  else
 
    sprintf(out
, "Mat%.2d", (MATE 
- Abs
(value
)) / 2);  
  return out;
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   DisplayPath() is used to display a PV during the root move search.        *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
char *DisplayPath(TREE * RESTRICT tree, int wtm, PATH * pv) {
 
  static char buffer[4096];
 
  int i, t_move_number;
 
 
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Initialize.                                             *
 
 *                                                          *
 
 ************************************************************
 
 */
 
  t_move_number = move_number;
 
  sprintf(buffer
, " %d.", move_number
);  
  if (!wtm)
 
  for (i = 1; i < (int) pv->pathl; i++) {
 
    if (i > 1 && wtm)
 
            pv->path[i]));
 
    MakeMove(tree, i, wtm, pv->path[i]);
 
    wtm = Flip(wtm);
 
    if (wtm)
 
      t_move_number++;
 
  }
 
  if (pv->pathh == 1)
 
  else if (pv->pathh == 2)
 
  else if (pv->pathh == 3)
 
  else if (pv->pathh == 4)
 
    for (i 
= 0; i 
< 30 - (int) strlen(buffer
); i
++) // Pierre-Marie Baty -- added type cast  
  for (i = pv->pathl - 1; i > 0; i--) {
 
    wtm = Flip(wtm);
 
    UnmakeMove(tree, i, wtm, pv->path[i]);
 
  }
 
  return buffer;
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   DisplayFail() is used to display a PV (moves only) during the search.     *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
void DisplayFail
(TREE 
* RESTRICT tree
, int type
, int level
, int wtm
, int time,  
    int move, int value, int force) {
 
  char buffer[4096], *fh_indicator;
 
 
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  If we have not used "noise_level" units of time, we     *
 
 *  return immediately.  Otherwise we add the fail high/low *
 
 *  indicator (++/--) and then display the times.           *
 
 *                                                          *
 
 ************************************************************
 
 */
 
  if (time < (int) noise_level
) // Pierre-Marie Baty -- added type cast  
    return;
 
  if (type == 1)
 
    fh_indicator = (wtm) ? "++" : "--";
 
  else
 
    fh_indicator = (wtm) ? "--" : "++";
 
  Print(4, "         %2i   %s     %2s   ", iteration,
 
      Display2Times(end_time - start_time), fh_indicator);
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  If we are pondering, we need to add the (ponder-move)   *
 
 *  to the front of the buffer, correcting the move number  *
 
 *  if necessary.  Then fill in the move number and the     *
 
 *  fail high/low bound.                                    *
 
 *                                                          *
 
 ************************************************************
 
 */
 
  if (!pondering) {
 
    sprintf(buffer
, "%d.", move_number
);  
    if (!wtm)
 
  } else {
 
    if (wtm)
 
      sprintf(buffer
, "%d. ... (%s) %d.", move_number 
- 1, ponder_text
,  
          move_number);
 
    else
 
      sprintf(buffer
, "%d. (%s)", move_number
, ponder_text
);  
  }
 
  sprintf(buffer 
+ strlen(buffer
), " %s%c", OutputMove
(tree
, 1, wtm
, move
),  
      (type == 1) ? '!' : '?');
 
  if (time >= (int) noise_level 
|| force
) { // Pierre-Marie Baty -- added type cast  
    noise_block = 0;
 
    Lock(lock_io);
 
    Print(4, "%s", buffer);
 
    Unlock(lock_io);
 
    if (type == 1)
 
      Print(4, " (%c%s)                   \n", (wtm) ? '>' : '<',
 
          DisplayEvaluationKibitz(value, wtm));
 
    else
 
      Print(4, " (%c%s)                   \n", (wtm) ? '<' : '>',
 
          DisplayEvaluationKibitz(value, wtm));
 
  }
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   DisplayPV() is used to display a PV during the search.                    *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
void DisplayPV
(TREE 
* RESTRICT tree
, int level
, int wtm
, int time, PATH 
* pv
,  
    int force) {
 
  char buffer[4096], *buffp, *bufftemp;
 
  char blanks[40] = { "                                        " };
 
  int i, len, t_move_number, nskip = 0, twtm = wtm, pv_depth = pv->pathd;;
 
  unsigned int idle_time;
 
 
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Initialize.                                             *
 
 *                                                          *
 
 ************************************************************
 
 */
 
  for (i = 0; i < n_root_moves; i++)
 
    if (root_moves[i].status & 4)
 
      nskip++;
 
  for (i = 0; i < 4096; i++)
 
    buffer[i] = ' ';
 
  t_move_number = move_number;
 
  if (!pondering || analyze_mode) {
 
    sprintf(buffer
, "%d.", move_number
);  
    if (!wtm)
 
  } else {
 
    if (wtm)
 
      sprintf(buffer
, "%d. ... (%s) %d.", move_number 
- 1, ponder_text
,  
          move_number);
 
    else
 
      sprintf(buffer
, "%d. (%s)", move_number
, ponder_text
);  
  }
 
  for (i = 1; i < (int) pv->pathl; i++) {
 
    if (i > 1 && wtm)
 
            pv->path[i]));
 
    MakeMove(tree, i, wtm, pv->path[i]);
 
    wtm = Flip(wtm);
 
    if (wtm)
 
      t_move_number++;
 
  }
 
  if (pv->pathh == 1)
 
  else if (pv->pathh == 2)
 
  else if (pv->pathh == 3)
 
  else if (pv->pathh == 3)
 
  if (nskip > 1 && smp_max_threads > 1)
 
    for (i = 0; i < len; i++)
 
  }
 
  if (time >= (int) noise_level 
|| force
) { // Pierre-Marie Baty -- added type cast  
    noise_block = 0;
 
    Lock(lock_io);
 
    Print(2, "         ");
 
    if (level == 6)
 
      Print
(2, "%2i   %s%s   ", pv_depth
, Display2Times
(time), 
          DisplayEvaluation(pv->pathv, twtm));
 
    else
 
      Print
(2, "%2i-> %s%s   ", pv_depth
, Display2Times
(time) 
          , DisplayEvaluation(pv->pathv, twtm));
 
    buffp = buffer;
 
    do {
 
      if ((int) strlen(buffp
) > line_length 
- 38) {  
        bufftemp = buffp + line_length - 38;
 
        while (*bufftemp != ' ')
 
          bufftemp--;
 
        if (*(bufftemp - 1) == '.')
 
          while (*(--bufftemp) != ' ');
 
      } else
 
        bufftemp = 0;
 
      if (bufftemp)
 
        *bufftemp = 0;
 
      Print(2, "%s\n", buffp);
 
      buffp = bufftemp + 1;
 
      if (bufftemp)
 
          bufftemp = 0;
 
      if (bufftemp)
 
        Print(2, "                                     ");
 
    } while (bufftemp);
 
    idle_time = 0;
 
    for (i = 0; i < (int) smp_max_threads; i++) // Pierre-Marie Baty -- added type cast
 
      idle_time += thread[i].idle;
 
    busy_percent =
 
        100 - Min(100,
 
        100 * idle_time / (smp_max_threads * (end_time - start_time) + 1));
 
    Kibitz(level, twtm, pv_depth, end_time - start_time, pv->pathv,
 
        tree->nodes_searched, busy_percent, (int) tree->egtb_hits, kibitz_text); // Pierre-Marie Baty -- added type cast
 
    Unlock(lock_io);
 
  }
 
  for (i = pv->pathl - 1; i > 0; i--) {
 
    wtm = Flip(wtm);
 
    UnmakeMove(tree, i, wtm, pv->path[i]);
 
  }
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   DisplayHHMMSS is used to convert integer time values in 1/100th second    *
 
 *   units into a traditional output format for time, hh:mm:ss rather than     *
 
 *   just nnn.n seconds.                                                       *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
char *DisplayHHMMSS
(unsigned int time) {  
  static char out[32];
 
 
 
  return out;
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   DisplayHHMM is used to convert integer time values in 1/100th second      *
 
 *   units into a traditional output format for time, mm:ss rather than just   *
 
 *   nnn.n seconds.                                                            *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
char *DisplayHHMM
(unsigned int time) {  
  static char out[10];
 
 
 
  return out;
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   DisplayKMB() takes an integer value that represents nodes per second, or  *
 
 *   just total nodes, and converts it into a more compact form, so that       *
 
 *   instead of nps=57200931, we get nps=57.2M.  We use units of "K", "M",     *
 
 *   "B" and "T".  If type==0, K=1000, etc.  If type=1, K=1024, etc.           *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
char *DisplayKMB(uint64_t val, int type) {
 
  static char out[10];
 
 
 
  if (type == 0) {
 
    if (val < 1000)
 
    else if (val < 1000000)
 
      sprintf(out
, "%.1fK", (double) val 
/ 1000);  
    else if (val < 1000000000)
 
      sprintf(out
, "%.1fM", (double) val 
/ 1000000);  
    else
 
      sprintf(out
, "%.1fB", (double) val 
/ 1000000000);  
  } else {
 
    if (val > 0 && !(val & 0x000000003fffffffULL))
 
      sprintf(out
, "%dG", (int) (val 
/ (1 << 30)));  
    else if (val > 0 && !(val & 0x00000000000fffffULL))
 
      sprintf(out
, "%dM", (int) (val 
/ (1 << 20)));  
    else if (val > 0 && !(val & 0x00000000000003ffULL))
 
      sprintf(out
, "%dK", (int) (val 
/ (1 << 10)));  
    else
 
  }
 
  return out;
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   DisplayTime() is used to display search times, and shows times in one of  *
 
 *   two ways depending on the value passed in.  If less than 60 seconds is to *
 
 *   be displayed, it is displayed as a decimal fraction like 32.7, while if   *
 
 *   more than 60 seconds is to be displayed, it is converted to the more      *
 
 *   traditional mm:ss form.  The string it produces is of fixed length to     *
 
 *   provide neater screen formatting.                                         *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
char *DisplayTime
(unsigned int time) {  
  static char out[10];
 
 
 
  else {
 
  }
 
  return out;
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   Display2Times() is used to display search times, and shows times in one   *
 
 *   of two ways depending on the value passed in.  If less than 60 seconds is *
 
 *   to be displayed, it is displayed as a decimal fraction like 32.7, while   *
 
 *   if more than 60 seconds is to be displayed, it is converted to the more   *
 
 *   traditional mm:ss form.  The string it produces is of fixed length to     *
 
 *   provide neater screen formatting.                                         *
 
 *                                                                             *
 
 *   The second argument is the "difficulty" value which lets us display the   *
 
 *   target time (as modified by difficulty) so that it is possible to know    *
 
 *   roughly when the move will be announced.                                  *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
char *Display2Times
(unsigned int time) {  
  int ttime, c, spaces;
 
  static char out[20], tout[10];
 
 
 
  else {
 
  }
 
  if (search_time_limit)
 
    ttime = search_time_limit;
 
  else
 
    ttime = difficulty * time_limit / 100;
 
  if (ttime < 360000) {
 
    if (ttime < 6000)
 
      sprintf(tout
, "%6.2f", (float) ttime 
/ 100.0);  
    else {
 
      ttime = ttime / 100;
 
      sprintf(tout
, "%3u:%02u", ttime 
/ 60, ttime 
% 60);  
    }
 
  }
 
  for (c = 0; c < spaces; c++)
 
  return out;
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   DisplayTimeKibitz() behaves just like DisplayTime() except that the       *
 
 *   string it produces is a variable-length string that is as short as        *
 
 *   possible to make ICC kibitzes/whispers look neater.                       *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
char *DisplayTimeKibitz
(unsigned int time) {  
  static char out[10];
 
 
 
  else {
 
  }
 
  return out;
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   EGTBPV() is used to display the PV for a known EGTB position.  It simply  *
 
 *   makes moves, looks up the position to find the shortest mate, then it     *
 
 *   follows that PV.  It appends a "!" to a move that is the only move to     *
 
 *   preserve the shortest path to mate (all other moves lead to longer mates  *
 
 *   or even draws.)                                                           *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
#if !defined(NOEGTB)
 
void EGTBPV(TREE * RESTRICT tree, int wtm) {
 
  uint64_t hk[1024], phk[1024], pos[1024];
 
  unsigned moves[1024], current[256], *last;
 
  int value, ply, i, j, nmoves;
 
  int t_move_number, best = 0, bestmv = 0, optimal_mv = 0, legal;
 
  char buffer[16384], *next;
 
 
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  First, see if this is a known EGTB position.  If not,   *
 
 *  we can bug out right now.                               *
 
 *                                                          *
 
 ************************************************************
 
 */
 
  if (!EGTB_setup)
 
    return;
 
  tree->status[1] = tree->status[0];
 
  if (Castle(1, white) + Castle(1, white))
 
    return;
 
  if (!EGTBProbe(tree, 1, wtm, &value))
 
    return;
 
  t_move_number = move_number;
 
  sprintf(buffer
, "%d.", move_number
);  
  if (!wtm)
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  The rest is simple, but messy.  Generate all moves,     *
 
 *  then find the move with the best egtb score and make it *
 
 *  (note that if there is only one that is optimal, it is  *
 
 *  flagged as such).  We then repeat this over and over    *
 
 *  until we reach the end, or until we repeat a move and   *
 
 *  can call it a repetition.                               *
 
 *                                                          *
 
 ************************************************************
 
 */
 
  for (ply = 1; ply < 1024; ply++) {
 
    pos[ply] = HashKey;
 
    last = GenerateCaptures(tree, 1, wtm, current);
 
    last = GenerateNoncaptures(tree, 1, wtm, last);
 
    nmoves = last - current;
 
    best = -MATE - 1;
 
    legal = 0;
 
    for (i = 0; i < nmoves; i++) {
 
      MakeMove(tree, 1, wtm, current[i]);
 
      if (!Check(wtm)) {
 
        legal++;
 
        if (TotalAllPieces == 2 || EGTBProbe(tree, 2, Flip(wtm), &value)) {
 
          if (TotalAllPieces > 2)
 
            value = -value;
 
          else
 
            value = DrawScore(wtm);
 
          if (value > best) {
 
            best = value;
 
            bestmv = current[i];
 
            optimal_mv = 1;
 
          } else if (value == best)
 
            optimal_mv = 0;
 
        }
 
      }
 
      UnmakeMove(tree, 1, wtm, current[i]);
 
    }
 
    if (best > -MATE - 1) {
 
      moves[ply] = bestmv;
 
      if (ply > 1 && wtm)
 
              bestmv));
 
      if (!strchr(buffer
, '#') && legal 
> 1 && optimal_mv
)  
      hk[ply] = HashKey;
 
      phk[ply] = PawnHashKey;
 
      MakeMove(tree, 1, wtm, bestmv);
 
      tree->status[1] = tree->status[2];
 
      wtm = Flip(wtm);
 
      for (j = 2 - (ply & 1); j < ply; j += 2)
 
        if (pos[ply] == pos[j])
 
          break;
 
      if (j < ply)
 
        break;
 
      if (wtm)
 
        t_move_number++;
 
        break;
 
    } else {
 
      ply--;
 
      break;
 
    }
 
  }
 
  nmoves = ply;
 
  for (; ply > 0; ply--) {
 
    wtm = Flip(wtm);
 
    tree->save_hash_key[1] = hk[ply];
 
    tree->save_pawn_hash_key[1] = phk[ply];
 
    UnmakeMove(tree, 1, wtm, moves[ply]);
 
    tree->status[2] = tree->status[1];
 
  }
 
  next = buffer;
 
  while (nmoves) {
 
    if ((int) strlen(next
) > line_length
) { // Pierre-Marie Baty -- added type cast  
      int i;
 
 
 
      for (i = 0; i < 16; i++)
 
        if (*(next + 64 + i) == ' ')
 
          break;
 
      *(next + 64 + i) = 0;
 
      next += 64 + i + 1;
 
    } else {
 
      break;
 
    }
 
  }
 
}
 
#endif
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   FormatPV() is used to display a PV during the search.  It will also note  *
 
 *   when the PV was terminated by a hash table hit.                           *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
char *FormatPV(TREE * RESTRICT tree, int wtm, PATH pv) {
 
  int i, t_move_number;
 
  static char buffer[4096];
 
 
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Initialize.                                             *
 
 *                                                          *
 
 ************************************************************
 
 */
 
  t_move_number = move_number;
 
  sprintf(buffer
, " %d.", move_number
);  
  if (!wtm)
 
  for (i = 1; i < (int) pv.pathl; i++) {
 
    if (i > 1 && wtm)
 
            pv.path[i]));
 
    MakeMove(tree, i, wtm, pv.path[i]);
 
    wtm = Flip(wtm);
 
    if (wtm)
 
      t_move_number++;
 
  }
 
  for (i = pv.pathl - 1; i > 0; i--) {
 
    wtm = Flip(wtm);
 
    UnmakeMove(tree, i, wtm, pv.path[i]);
 
  }
 
  return buffer;
 
}
 
 
 
/* last modified 02/26/14 */
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   GameOver() is used to determine if the game is over by rule.  More        *
 
 *   specifically, after our move, the opponent has no legal move to play.  He *
 
 *   is either checkmated or stalemated, either of which is sufficient reason  *
 
 *   to terminate the game.                                                    *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
int GameOver(int wtm) {
 
  TREE *const tree = block[0];
 
  unsigned *mvp, *lastm, rmoves[256], over = 1;
 
 
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  First, use GenerateMoves() to generate the set of       *
 
 *  legal moves from the root position.                     *
 
 *                                                          *
 
 ************************************************************
 
 */
 
  lastm = GenerateCaptures(tree, 1, wtm, rmoves);
 
  lastm = GenerateNoncaptures(tree, 1, wtm, lastm);
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Now make each move and determine if we are in check     *
 
 *  after each one.  Any move that does not leave us in     *
 
 *  check is good enough to prove that the game is not yet  *
 
 *  officially over.                                        *
 
 *                                                          *
 
 ************************************************************
 
 */
 
  for (mvp = rmoves; mvp < lastm; mvp++) {
 
    MakeMove(tree, 1, wtm, *mvp);
 
    if (!Check(wtm))
 
      over = 0;
 
    UnmakeMove(tree, 1, wtm, *mvp);
 
  }
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  If we did not make it thru the complete move list, we   *
 
 *  must have at least one legal move so the game is not    *
 
 *  over.  return 0.  Otherwise, we have no move and the    *
 
 *  game is over.  We return 1 if this side is stalmated or *
 
 *  we return 2 if this side is mated.                      *
 
 *                                                          *
 
 ************************************************************
 
 */
 
  if (!over)
 
    return 0;
 
  else if (!Check(wtm))
 
    return 1;
 
  else
 
    return 2;
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   ReadClock() is a procedure used to read the elapsed time.  Since this     *
 
 *   varies from system to system, this procedure has several flavors to       *
 
 *   provide portability.                                                      *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
unsigned int ReadClock(void) {
 
#if defined(UNIX)
 
  struct timeval timeval;
 
  struct timezone timezone;
 
#else
 
  //HANDLE hThread; // Pierre-Marie Baty -- unreferenced variable
 
  //FILETIME ftCreate, ftExit, ftKernel, ftUser; // Pierre-Marie Baty -- unreferenced variables
 
  //uint64_t tUser64; // Pierre-Marie Baty -- unreferenced variable
 
#endif
 
#if defined(UNIX)
 
  gettimeofday(&timeval, &timezone);
 
  return timeval.tv_sec * 100 + (timeval.tv_usec / 10000);
 
#else
 
  return (unsigned int) GetTickCount() / 10;
 
#endif
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   FindBlockID() converts a thread block pointer into an ID that is easier   *
 
 *   to understand when debugging.                                             *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
int FindBlockID(TREE * RESTRICT which) {
 
  int i;
 
 
 
  for (i = 0; i <= (int) smp_max_threads * 64; i++) // Pierre-Marie Baty -- added type cast
 
    if (which == block[i])
 
      return i;
 
  return -1;
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   InvalidPosition() is used to determine if the position just entered via a *
 
 *   FEN-string or the "edit" command is legal.  This includes the expected    *
 
 *   tests for too many pawns or pieces for one side, pawns on impossible      *
 
 *   squares, and the like.                                                    *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
int InvalidPosition(TREE * RESTRICT tree) {
 
  int error = 0, wp, wn, wb, wr, wq, wk, bp, bn, bb, br, bq, bk;
 
 
 
  wp = PopCnt(Pawns(white));
 
  wn = PopCnt(Knights(white));
 
  wb = PopCnt(Bishops(white));
 
  wr = PopCnt(Rooks(white));
 
  wq = PopCnt(Queens(white));
 
  wk = PopCnt(Kings(white));
 
  bp = PopCnt(Pawns(black));
 
  bn = PopCnt(Knights(black));
 
  bb = PopCnt(Bishops(black));
 
  br = PopCnt(Rooks(black));
 
  bq = PopCnt(Queens(black));
 
  bk = PopCnt(Kings(black));
 
  if (wp > 8) {
 
    Print(4095, "illegal position, too many white pawns\n");
 
    error = 1;
 
  }
 
  if (wn && wp + wn > 10) {
 
    Print(4095, "illegal position, too many white knights\n");
 
    error = 1;
 
  }
 
  if (wb && wp + wb > 10) {
 
    Print(4095, "illegal position, too many white bishops\n");
 
    error = 1;
 
  }
 
  if (wr && wp + wr > 10) {
 
    Print(4095, "illegal position, too many white rooks\n");
 
    error = 1;
 
  }
 
  if (wq && wp + wq > 10) {
 
    Print(4095, "illegal position, too many white queens\n");
 
    error = 1;
 
  }
 
  if (wk == 0) {
 
    Print(4095, "illegal position, no white king\n");
 
    error = 1;
 
  }
 
  if (wk > 1) {
 
    Print(4095, "illegal position, multiple white kings\n");
 
    error = 1;
 
  }
 
  if ((wn + wb + wr + wq) && wp + wn + wb + wr + wq > 15) {
 
    Print(4095, "illegal position, too many white pieces\n");
 
    error = 1;
 
  }
 
  if (Pawns(white) & (rank_mask[RANK1] | rank_mask[RANK8])) {
 
    Print(4095, "illegal position, white pawns on first/eighth rank(s)\n");
 
    error = 1;
 
  }
 
  if (bp > 8) {
 
    Print(4095, "illegal position, too many black pawns\n");
 
    error = 1;
 
  }
 
  if (bn && bp + bn > 10) {
 
    Print(4095, "illegal position, too many black knights\n");
 
    error = 1;
 
  }
 
  if (bb && bp + bb > 10) {
 
    Print(4095, "illegal position, too many black bishops\n");
 
    error = 1;
 
  }
 
  if (br && bp + br > 10) {
 
    Print(4095, "illegal position, too many black rooks\n");
 
    error = 1;
 
  }
 
  if (bq && bp + bq > 10) {
 
    Print(4095, "illegal position, too many black queens\n");
 
    error = 1;
 
  }
 
  if (bk == 0) {
 
    Print(4095, "illegal position, no black king\n");
 
    error = 1;
 
  }
 
  if (bk > 1) {
 
    Print(4095, "illegal position, multiple black kings\n");
 
    error = 1;
 
  }
 
  if ((bn + bb + br + bq) && bp + bn + bb + br + bq > 15) {
 
    Print(4095, "illegal position, too many black pieces\n");
 
    error = 1;
 
  }
 
  if (Pawns(black) & (rank_mask[RANK1] | rank_mask[RANK8])) {
 
    Print(4095, "illegal position, black pawns on first/eighth rank(s)\n");
 
    error = 1;
 
  }
 
  if (error == 0 && Check(!game_wtm)) {
 
    Print(4095, "ERROR side not on move is in check!\n");
 
    error = 1;
 
  }
 
  return error;
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   KingPawnSquare() is used to initialize some of the passed pawn race       *
 
 *   tables used by Evaluate().  It simply answers the question "is the king   *
 
 *   in the square of the pawn so the pawn can't outrun it and promote?"       *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
int KingPawnSquare(int pawn, int king, int queen, int ptm) {
 
  int pdist, kdist;
 
 
 
  pdist = Abs(Rank(pawn) - Rank(queen)) + !ptm;
 
  kdist = Distance(king, queen);
 
  return pdist >= kdist;
 
}
 
 
 
/* last modified 02/26/14 */
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   NewGame() is used to initialize the chess position and timing controls to *
 
 *   the setup needed to start a new game.                                     *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
void NewGame(int save) {
 
  TREE *const tree = block[0];
 
  static int save_book_selection_width = 5, save_kibitz = 0;
 
  static int save_resign = 0, save_resign_count = 0, save_draw_count = 0;
 
  static int save_learning = 0, save_learn = 0, save_accept_draws = 0;
 
  int id;
 
 
 
  new_game = 0;
 
  if (save) {
 
    save_book_selection_width = book_selection_width;
 
    save_kibitz = kibitz;
 
    save_resign = resign;
 
    save_resign_count = resign_count;
 
    save_draw_count = draw_count;
 
    save_learning = learning;
 
    save_learn = learn;
 
    save_accept_draws = accept_draws;
 
  } else {
 
    if (learn && moves_out_of_book) {
 
      learn_value =
 
          (crafty_is_white) ? last_search_value : -last_search_value;
 
      LearnBook();
 
    }
 
    if (xboard) {
 
      printf("tellicsnoalias set 1 Crafty v%s (%d cpus)\n", version
, Max
(1,  
              smp_max_threads));
 
    }
 
    over = 0;
 
    moves_out_of_book = 0;
 
    learn_positions_count = 0;
 
    learn_value = 0;
 
    ponder_move = 0;
 
    last_search_value = 0;
 
    last_pv.pathd = 0;
 
    last_pv.pathl = 0;
 
    InitializeChessBoard(tree);
 
    InitializeHashTables(0);
 
    force = 0;
 
    books_file = normal_bs_file;
 
    draw_score[0] = 0;
 
    draw_score[1] = 0;
 
    game_wtm = 1;
 
    move_number = 1;
 
    tc_time_remaining[white] = tc_time;
 
    tc_time_remaining[black] = tc_time;
 
    tc_moves_remaining[white] = tc_moves;
 
    tc_moves_remaining[black] = tc_moves;
 
    if (move_actually_played) {
 
      if (log_file) {
 
        id = InitializeGetLogID();
 
        sprintf(log_filename
, "%s/log.%03d", log_path
, id
);  
        sprintf(history_filename
, "%s/game.%03d", log_path
, id
);  
        log_file 
= fopen(log_filename
, "w"); 
        history_file 
= fopen(history_filename
, "w+"); 
        if (!history_file) {
 
          printf("ERROR, unable to open game history file, exiting\n");  
          CraftyExit(1);
 
        }
 
      }
 
    }
 
    move_actually_played = 0;
 
    book_selection_width = save_book_selection_width;
 
    kibitz = save_kibitz;
 
    resign = save_resign;
 
    resign_count = save_resign_count;
 
    resign_counter = 0;
 
    draw_count = save_draw_count;
 
    accept_draws = save_accept_draws;
 
    draw_counter = 0;
 
    usage_level = 0;
 
    learning = save_learning;
 
    learn = save_learn;
 
    predicted = 0;
 
    kibitz_depth = 0;
 
    tree->nodes_searched = 0;
 
    kibitz_text[0] = 0;
 
  }
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   ParseTime() is used to parse a time value that could be entered as s.ss,  *
 
 *   mm:ss, or hh:mm:ss.  It is converted to Crafty's internal 1/100th second  *
 
 *   time resolution.                                                          *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
int ParseTime(char *string) {
 
  int time = 0, minutes 
= 0;  
 
 
  while (*string) {
 
    switch (*string) {
 
      case '0':
 
      case '1':
 
      case '2':
 
      case '3':
 
      case '4':
 
      case '5':
 
      case '6':
 
      case '7':
 
      case '8':
 
      case '9':
 
        minutes = minutes * 10 + (*string) - '0';
 
        break;
 
      case ':':
 
        minutes = 0;
 
        break;
 
      default:
 
        Print(4095, "illegal character in time, please re-enter\n");
 
        break;
 
    }
 
    string++;
 
  }
 
  return time * 60 + minutes
;  
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   Pass() was written by Tim Mann to handle the case where a position is set *
 
 *   using a FEN string, and then black moves first.  The game.nnn file was    *
 
 *   designed to start with a white move, so "pass" is now a "no-op" move for  *
 
 *   the side whose turn it is to move.                                        *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
void Pass(void) {
 
  const int halfmoves_done = 2 * (move_number - 1) + (1 - game_wtm);
 
  int prev_pass = 0;
 
  char buffer[128];
 
 
 
/* Was previous move a pass? */
 
  if (halfmoves_done > 0) {
 
    if (history_file) {
 
      fseek(history_file
, (halfmoves_done 
- 1) * 10, SEEK_SET
);  
      if (fscanf(history_file
, "%s", buffer
) == 0 ||  
        prev_pass = 1;
 
    }
 
  }
 
  if (prev_pass) {
 
    if (game_wtm)
 
      move_number--;
 
  } else {
 
    if (history_file) {
 
      fseek(history_file
, halfmoves_done 
* 10, SEEK_SET
);  
      fprintf(history_file
, "%9s\n", "pass");  
    }
 
    if (!game_wtm)
 
      move_number++;
 
  }
 
  game_wtm = Flip(game_wtm);
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   Print() is the main output procedure.  The first argument is a bitmask    *
 
 *   that identifies the type of output.  If this argument is anded with the   *
 
 *   "display" control variable, and a non-zero result is produced, then the   *
 
 *   print is done, otherwise the print is skipped and we return (more details *
 
 *   can be found in the display command comments in option.c).  This also     *
 
 *   uses the "variable number of arguments" facility in ANSI C since the      *
 
 *   normal printf() function accepts a variable number of arguments.          *
 
 *                                                                             *
 
 *   Print() also sends output to the log.nnn file automatically, so that it   *
 
 *   is recorded even if the above display control variable says "do not send  *
 
 *   this to stdout"                                                           *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
void Print(int vb, char *fmt, ...) {
 
  va_list ap;
 
 
 
  if (vb == 4095 || vb & display_options) {
 
  }
 
  if (time_limit > 5 || tc_time_remaining[root_wtm] > 1000 || vb == 4095) {
 
    if (log_file) {
 
    }
 
  }
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *  A 32 bit random number generator. An implementation in C of the algorithm  *
 
 *  given by Knuth, the art of computer programming, vol. 2, pp. 26-27. We use *
 
 *  e=32, so we have to evaluate y(n) = y(n - 24) + y(n - 55) mod 2^32, which  *
 
 *  is implicitly done by unsigned arithmetic.                                 *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
unsigned int Random32(void) {
 
/*
 
 random numbers from Mathematica 2.0.
 
 SeedRandom = 1;
 
 Table[Random[Integer, {0, 2^32 - 1}]
 
 */
 
  static const uint64_t x[55] = {
 
    1410651636UL, 3012776752UL, 3497475623UL, 2892145026UL, 1571949714UL,
 
    3253082284UL, 3489895018UL, 387949491UL, 2597396737UL, 1981903553UL,
 
    3160251843UL, 129444464UL, 1851443344UL, 4156445905UL, 224604922UL,
 
    1455067070UL, 3953493484UL, 1460937157UL, 2528362617UL, 317430674UL,
 
    3229354360UL, 117491133UL, 832845075UL, 1961600170UL, 1321557429UL,
 
    747750121UL, 545747446UL, 810476036UL, 503334515UL, 4088144633UL,
 
    2824216555UL, 3738252341UL, 3493754131UL, 3672533954UL, 29494241UL,
 
    1180928407UL, 4213624418UL, 33062851UL, 3221315737UL, 1145213552UL,
 
    2957984897UL, 4078668503UL, 2262661702UL, 65478801UL, 2527208841UL,
 
    1960622036UL, 315685891UL, 1196037864UL, 804614524UL, 1421733266UL,
 
    2017105031UL, 3882325900UL, 810735053UL, 384606609UL, 2393861397UL
 
  };
 
  static int init = 1;
 
  static uint64_t y[55];
 
  static int j, k;
 
  uint64_t ul;
 
 
 
  if (init) {
 
    int i;
 
 
 
    init = 0;
 
    for (i = 0; i < 55; i++)
 
      y[i] = x[i];
 
    j = 24 - 1;
 
    k = 55 - 1;
 
  }
 
  ul = (y[k] += y[j]);
 
  if (--j < 0)
 
    j = 55 - 1;
 
  if (--k < 0)
 
    k = 55 - 1;
 
  return (unsigned int) ul;
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   Random64() uses two calls to Random32() and then concatenates the two     *
 
 *   values into one 64 bit random number, used for hash signature updates on  *
 
 *   the Zobrist hash signatures.                                              *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
uint64_t Random64(void) {
 
  uint64_t result;
 
  unsigned int r1, r2;
 
 
 
  r1 = Random32();
 
  r2 = Random32();
 
  result = r1 | (uint64_t) r2 << 32;
 
  return result;
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   Read() copies data from the command_buffer into a local buffer, and then  *
 
 *   uses ReadParse to break this command up into tokens for processing.       *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
int Read(int wait, char *buffer) {
 
  char *eol, *ret, readdata;
 
 
 
  *buffer = 0;
 
/*
 
 case 1:  We have a complete command line, with terminating
 
 N/L character in the buffer.  We can simply extract it from
 
 the I/O buffer, parse it and return.
 
 */
 
  if (strchr(cmd_buffer
, '\n'));  
/*
 
 case 2:  The buffer does not contain a complete line.  If we
 
 were asked to not wait for a complete command, then we first
 
 see if I/O is possible, and if so, read in what is available.
 
 If that includes a N/L, then we are ready to parse and return.
 
 If not, we return indicating no input available just yet.
 
 */
 
  else if (!wait) {
 
    if (CheckInput()) {
 
      readdata = ReadInput();
 
      if (!strchr(cmd_buffer
, '\n'))  
        return 0;
 
      if (!readdata)
 
        return -1;
 
    } else
 
      return 0;
 
  }
 
/*
 
 case 3:  The buffer does not contain a complete line, but we
 
 were asked to wait until a complete command is entered.  So we
 
 hang by doing a ReadInput() and continue doing so until we get
 
 a N/L character in the buffer.  Then we parse and return.
 
 */
 
  else
 
    while (!strchr(cmd_buffer
, '\n')) {  
      readdata = ReadInput();
 
      if (!readdata)
 
        return -1;
 
    }
 
  eol 
= strchr(cmd_buffer
, '\n'); 
  *eol = 0;
 
  ret 
= strchr(cmd_buffer
, '\r'); 
  if (ret)
 
    *ret = ' ';
 
  return 1;
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   ReadClear() clears the input buffer when input_stream is being switched   *
 
 *   to a file, since we have info buffered up from a different input stream.  *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
void ReadClear() {
 
  cmd_buffer[0] = 0;
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   ReadParse() takes one complete command-line, and breaks it up into tokens.*
 
 *   common delimiters are used, such as " ", ",", "/" and ";", any of which   *
 
 *   delimit fields.                                                           *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
int ReadParse(char *buffer, char *args[], char *delims) {
 
  int nargs;
 
  char *next, tbuffer[4096];
 
 
 
  for (nargs = 0; nargs < 512; nargs++)
 
    *(args[nargs]) = 0;
 
  next 
= strtok(tbuffer
, delims
); 
  if (!next)
 
    return 0;
 
    Print(4095, "ERROR, ignoring token %s, max allowable len = 255\n", next);
 
  else
 
  for (nargs = 1; nargs < 512; nargs++) {
 
    if (!next)
 
      break;
 
      Print(4095, "ERROR, ignoring token %s, max allowable len = 255\n",
 
          next);
 
    else
 
  }
 
  return nargs;
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   ReadInput() reads data from the input_stream, and buffers this into the   *
 
 *   command_buffer for later processing.                                      *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
int ReadInput(void) {
 
  int bytes;
 
  char buffer[4096], *end;
 
 
 
  do
 
    bytes = _read(_fileno(input_stream), buffer, 2048); // Pierre-Marie Baty -- POSIX/ISO C++ names fixes
 
  while (bytes < 0 && errno == EINTR);
 
  if (bytes == 0) {
 
    if (input_stream != stdin)
 
    input_stream = stdin;
 
    return 0;
 
  } else if (bytes < 0) {
 
    Print(4095, "ERROR!  input I/O stream is unreadable, exiting.\n");
 
    CraftyExit(1);
 
  }
 
  end 
= cmd_buffer 
+ strlen(cmd_buffer
); 
  *(end + bytes) = 0;
 
  return 1;
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   ReadChessMove() is used to read a move from an input file.  The main      *
 
 *   issue is to skip over "trash" like move numbers, times, comments, and so  *
 
 *   forth, and find the next actual move.                                     *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
int ReadChessMove(TREE * RESTRICT tree, FILE * input, int wtm, int one_move) {
 
  int move = 0, status;
 
  static char text[128];
 
  char *tmove;
 
 
 
  while (move == 0) {
 
    status 
= fscanf(input
, "%s", text
); 
    if (status <= 0)
 
      return -1;
 
      tmove 
= text 
+ strspn(text
, "0123456789."); 
    else
 
      tmove = text;
 
    if (((tmove[0] >= 'a' && tmove[0] <= 'z') || (tmove[0] >= 'A' &&
 
                tmove
[0] <= 'Z')) || !strcmp(tmove
, "0-0") 
        return -1;
 
      move = InputMove(tree, 0, wtm, 1, 0, tmove);
 
    }
 
    if (one_move)
 
      break;
 
  }
 
  return move;
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   ReadNextMove() is used to take a text chess move from a file, and see if  *
 
 *   if is legal, skipping a sometimes embedded move number (1.e4 for example) *
 
 *   to make PGN import easier.                                                *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
int ReadNextMove(TREE * RESTRICT tree, char *text, int ply, int wtm) {
 
  char *tmove;
 
  int move = 0;
 
 
 
    tmove 
= text 
+ strspn(text
, "0123456789./-"); 
  else
 
    tmove = text;
 
  if (((tmove[0] >= 'a' && tmove[0] <= 'z') || (tmove[0] >= 'A' &&
 
              tmove
[0] <= 'Z')) || !strcmp(tmove
, "0-0") 
      return -1;
 
    move = InputMove(tree, ply, wtm, 1, 0, tmove);
 
  }
 
  return move;
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   This routine reads a move from a PGN file to build an opening book or for *
 
 *   annotating.  It returns a 1 if a header is read, it returns a 0 if a move *
 
 *   is read, and returns a -1 on end of file.  It counts lines and this       *
 
 *   counter can be accessed by calling this function with a non-zero second   *
 
 *   formal parameter.                                                         *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
int ReadPGN(FILE * input, int option) {
 
  static int data = 0, lines_read = 0;
 
  int braces = 0, parens = 0, brackets = 0, analysis = 0, last_good_line;
 
  static char input_buffer[4096];
 
  char *eof, analysis_move[64];
 
 
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  If the line counter is being requested, return it with  *
 
 *  no other changes being made.  If "purge" is true, clear *
 
 *  the current input buffer.                               *
 
 *                                                          *
 
 ************************************************************
 
 */
 
  pgn_suggested_percent = 0;
 
  if (!input) {
 
    lines_read = 0;
 
    data = 0;
 
    return 0;
 
  }
 
  if (option == -1)
 
    data = 0;
 
  if (option == -2)
 
    return lines_read;
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  If we don't have any data in the buffer, the first step *
 
 *  is to read the next line.                               *
 
 *                                                          *
 
 ************************************************************
 
 */
 
  while (1) {
 
    if (!data) {
 
      eof 
= fgets(input_buffer
, 4096, input
); 
      if (!eof)
 
        return -1;
 
      if (strchr(input_buffer
, '\n'))  
        *strchr(input_buffer
, '\n') = 0;  
      if (strchr(input_buffer
, '\r'))  
        *strchr(input_buffer
, '\r') = ' ';  
      lines_read++;
 
      buffer[0] = 0;
 
      sscanf(input_buffer
, "%s", buffer
);  
      if (buffer[0] == '[')
 
        do {
 
          char *bracket1, *bracket2, value[128];
 
 
 
          bracket1 
= strchr(input_buffer
, '\"'); 
          if (bracket1 == 0)
 
            return 1;
 
          bracket2 
= strchr(bracket1 
+ 1, '\"'); 
          if (bracket2 == 0)
 
            return 1;
 
          *bracket1 = 0;
 
          *bracket2 = 0;
 
          if (strstr(input_buffer
, "Event"))  
          else if (strstr(input_buffer
, "Site"))  
          else if (strstr(input_buffer
, "Round"))  
          else if (strstr(input_buffer
, "Date"))  
          else if (strstr(input_buffer
, "WhiteElo"))  
          else if (strstr(input_buffer
, "White"))  
          else if (strstr(input_buffer
, "BlackElo"))  
          else if (strstr(input_buffer
, "Black"))  
          else if (strstr(input_buffer
, "Result"))  
          else if (strstr(input_buffer
, "FEN")) {  
            sprintf(buffer
, "setboard %s", value
);  
            Option(block[0]);
 
            continue;
 
          }
 
          return 1;
 
        } while (0);
 
      data = 1;
 
    }
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  If we already have data in the buffer, it is just a     *
 
 *  matter of extracting the next move and returning it to  *
 
 *  the caller.  If the buffer is empty, another line has   *
 
 *  to be read in.                                          *
 
 *                                                          *
 
 ************************************************************
 
 */
 
    else {
 
      buffer[0] = 0;
 
      sscanf(input_buffer
, "%s", buffer
);  
        data = 0;
 
        continue;
 
      } else {
 
        char *skip;
 
 
 
        if (skip)
 
      }
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  This skips over nested {} or () characters and finds    *
 
 *  the 'mate', before returning any more moves.  It also   *
 
 *  stops if a PGN header is encountered, probably due to   *
 
 *  an incorrectly bracketed analysis variation.            *
 
 *                                                          *
 
 ************************************************************
 
 */
 
      last_good_line = lines_read;
 
      analysis_move[0] = 0;
 
        while (1) {
 
          char *skip, *ch;
 
 
 
          analysis = 1;
 
          while ((ch 
= strpbrk(buffer
, "(){}[]"))) {  
            if (*ch == '(') {
 
              if (!braces)
 
                parens++;
 
            }
 
            if (*ch == ')') {
 
              if (!braces)
 
                parens--;
 
            }
 
            if (*ch == '{') {
 
              braces++;
 
            }
 
            if (*ch == '}') {
 
              braces--;
 
            }
 
            if (*ch == '[') {
 
              if (!braces)
 
                brackets++;
 
            }
 
            if (*ch == ']') {
 
              if (!braces)
 
                brackets--;
 
            }
 
          }
 
          if (analysis && analysis_move[0] == 0) {
 
              char *tmove = analysis_move;
 
 
 
              sscanf(buffer
, "%64s", analysis_move
);  
              strcpy(buffer
, analysis_move
);  
                tmove 
= buffer 
+ strspn(buffer
, "0123456789."); 
              else
 
                tmove = buffer;
 
              if ((tmove[0] >= 'a' && tmove[0] <= 'z') || (tmove[0] >= 'A' &&
 
                      tmove
[0] <= 'Z') || !strcmp(tmove
, "0-0") 
                strcpy(analysis_move
, buffer
);  
              else
 
                analysis_move[0] = 0;
 
            }
 
          }
 
          if (parens == 0 && braces == 0 && brackets == 0)
 
            break;
 
          buffer[0] = 0;
 
          sscanf(input_buffer
, "%s", buffer
);  
            eof 
= fgets(input_buffer
, 4096, input
); 
            if (!eof) {
 
              parens = 0;
 
              braces = 0;
 
              brackets = 0;
 
              return -1;
 
            }
 
            if (strchr(input_buffer
, '\n'))  
              *strchr(input_buffer
, '\n') = 0;  
            if (strchr(input_buffer
, '\r'))  
              *strchr(input_buffer
, '\r') = ' ';  
            lines_read++;
 
            if (lines_read - last_good_line >= 100) {
 
              parens = 0;
 
              braces = 0;
 
              brackets = 0;
 
              Print(4095,
 
                  "ERROR.  comment spans over 100 lines, starting at line %d\n",
 
                  last_good_line);
 
              break;
 
            }
 
          }
 
      } else {
 
        int skip;
 
 
 
        if ((skip 
= strspn(buffer
, "0123456789./-"))) {  
          if (skip > 1)
 
        }
 
          char *first, *last, *percent;
 
 
 
          first 
= input_buffer 
+ strspn(input_buffer
, " "); 
          if (first == 0 || *first != '{')
 
            return 0;
 
          last 
= strchr(input_buffer
, '}'); 
          if (last == 0)
 
            return 0;
 
          percent 
= strstr(first
, "play"); 
          if (percent == 0)
 
            return 0;
 
          pgn_suggested_percent =
 
          return 0;
 
        }
 
      }
 
      if (analysis_move[0] && option == 1) {
 
        strcpy(buffer
, analysis_move
);  
        return 2;
 
      }
 
    }
 
  }
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   RestoreGame() resets the position to the beginning of the game, and then  *
 
 *   reads in the game.nnn history file to set the position up so that the     *
 
 *   game position matches the position at the end of the history file.        *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
void RestoreGame(void) {
 
  int i, v, move;
 
  char cmd[16];
 
 
 
  if (!history_file)
 
    return;
 
  game_wtm = 1;
 
  InitializeChessBoard(block[0]);
 
  for (i = 0; i < 500; i++) {
 
    fseek(history_file
, i 
* 10, SEEK_SET
);  
    v 
= fscanf(history_file
, "%s", cmd
); 
    if (v < 0)
 
      perror("RestoreGame fscanf error: ");  
      move = InputMove(block[0], 0, game_wtm, 1, 0, cmd);
 
      if (move)
 
        MakeMoveRoot(block[0], game_wtm, move);
 
      else
 
        break;
 
    }
 
    game_wtm = Flip(game_wtm);
 
  }
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   Kibitz() is used to whisper/kibitz information to a chess server.  It has *
 
 *   to handle the xboard whisper/kibitz interface.                            *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
void Kibitz
(int level
, int wtm
, int depth
, int time, int value
,  
    uint64_t nodes, int ip, int tb_hits, char *pv) {
 
  int nps;
 
 
 
  nps 
= (int) ((time) ? 100 * nodes 
/ (uint64_t) time : nodes
); 
  if (!puzzling) {
 
    char prefix[128];
 
 
 
    if (!(kibitz & 16))
 
    else
 
    switch (level) {
 
      case 1:
 
        if ((kibitz & 15) >= 1) {
 
          if (value > 0) {
 
            printf("%s mate in %d moves.\n\n", prefix
, value
);  
          }
 
          if (value < 0) {
 
            printf("%s mated in %d moves.\n\n", prefix
, -value
);  
          }
 
        }
 
        break;
 
      case 2:
 
        if ((kibitz & 15) >= 2)
 
          printf("%s ply=%d; eval=%s; nps=%s; time=%s(%d%%); egtb=%d\n",  
              prefix, depth, DisplayEvaluationKibitz(value, wtm),
 
              DisplayKMB
(nps
, 0), DisplayTimeKibitz
(time), ip
, tb_hits
); 
      case 3:
 
        if ((kibitz & 15) >= 3 && (nodes > 5000 || level == 2))
 
          printf("%s %s\n", prefix
, pv
);  
        break;
 
      case 4:
 
        if ((kibitz & 15) >= 4)
 
          printf("%s %s\n", prefix
, pv
);  
        break;
 
      case 5:
 
        if ((kibitz & 15) >= 5 && nodes > 5000) {
 
          printf("%s d%d-> %s/s %s(%d%%) %s %s ", prefix
, depth
,  
              DisplayKMB
(nps
, 0), DisplayTimeKibitz
(time), ip
, 
              DisplayEvaluationKibitz(value, wtm), pv);
 
          if (tb_hits)
 
        }
 
        break;
 
    }
 
    value = (wtm) ? value : -value;
 
    if (post && level > 1) {
 
        printf("      %2d  %5d %7d %" PRIu64 
" %s\n", depth
, value
, time,  
            nodes, pv + 10);
 
      else
 
        printf("      %2d  %5d %7d %" PRIu64 
" %s\n", depth
, value
, time,  
            nodes, pv);
 
    }
 
  }
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   Output() is used to print the principal variation whenever it changes.    *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
void Output(TREE * RESTRICT tree) {
 
  int wtm, i;
 
 
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Output the PV by walking down the path being backed up. *
 
 *  We do set the "age" for this move to "4" which will     *
 
 *  keep it in the group of "search with all threads" moves *
 
 *  so that it will be searched faster.                     *
 
 *                                                          *
 
 ************************************************************
 
 */
 
  wtm = root_wtm;
 
  if (!abort_search) {
 
    kibitz_depth = iteration;
 
    end_time = ReadClock();
 
    DisplayPV(tree, 6, wtm, end_time - start_time, &tree->pv[1], 0);
 
    for (i = 0; i < n_root_moves; i++)
 
      if (tree->pv[1].path[1] == root_moves[i].move)
 
        break;
 
    root_moves[i].path = tree->pv[1];
 
    root_moves[i].bm_age = 4;
 
  }
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   SortRootMoves() is used to sort the root move list based on the value     *
 
 *   saved for each move.  After a fail high or fail low, we always re-sort    *
 
 *   the root move list so that the best move found so far is first in the     *
 
 *   list.  This is primarily intended as a defense against getting a score    *
 
 *   for the first root move, and then getting a fail-high on the second move, *
 
 *   which should move this move to the front of the moves.  But if the move   *
 
 *   then fails low, we want to move it back down since a deeper/less-reduced  *
 
 *   search did not verify the fail-high.                                      *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
void SortRootMoves() {
 
  ROOT_MOVE rtemp;
 
  int mvp, done;
 
 
 
  do {
 
    done = 1;
 
    for (mvp = 0; mvp < n_root_moves - 1; mvp++) {
 
      if (root_moves[mvp].path.pathv < root_moves[mvp + 1].path.pathv) {
 
        rtemp = root_moves[mvp];
 
        root_moves[mvp] = root_moves[mvp + 1];
 
        root_moves[mvp + 1] = rtemp;
 
        done = 0;
 
      }
 
    }
 
  } while (!done);
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   Trace() is used to print the search trace output each time a node is      *
 
 *   traversed in the tree.                                                    *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
void Trace(TREE * RESTRICT tree, int ply, int depth, int wtm, int alpha,
 
    int beta, const char *name, int mode, int phase, int order) {
 
  int i;
 
 
 
  Lock(lock_io);
 
  for (i = 1; i < ply; i++)
 
    Print(-1, "  ");
 
  if (phase != EVALUATION) {
 
    Print(-1, "%d  %s(%d) d:%2d [%s,", ply, OutputMove(tree, ply, wtm,
 
            tree->curmv[ply]), order, depth, DisplayEvaluation(alpha, 1));
 
    Print(-1, "%s] n:%" PRIu64 " %s(%c:%d)", DisplayEvaluation(beta, 1),
 
        tree->nodes_searched, name, (mode) ? 'P' : 'S', phase);
 
    Print(-1, " (t=%d)\n", tree->thread_id);
 
  } else {
 
    Print(-1, "%d window/eval(%s) = {", ply, name);
 
    Print(-1, "%s, ", DisplayEvaluation(alpha, 1));
 
    Print(-1, "%s, ", DisplayEvaluation(depth, 1));
 
    Print(-1, "%s}\n", DisplayEvaluation(beta, 1));
 
  }
 
  Unlock(lock_io);
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   StrCnt() counts the number of times a character occurs in a string.       *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
int StrCnt(char *string, char testchar) {
 
  int count = 0, i;
 
 
 
  for (i 
= 0; i 
< (int) strlen(string
); i
++) // Pierre-Marie Baty -- added type cast  
    if (string[i] == testchar)
 
      count++;
 
  return count;
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   ValidMove() is used to verify that a move is playable.  It is mainly      *
 
 *   used to confirm that a move retrieved from the transposition/refutation   *
 
 *   and/or killer move is valid in the current position by checking the move  *
 
 *   against the current chess board, castling status, en passant status, etc. *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
int ValidMove(TREE * RESTRICT tree, int ply, int wtm, int move) {
 
  int btm = Flip(wtm);
 
 
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Make sure that the piece on <from> is the right color.  *
 
 *                                                          *
 
 ************************************************************
 
 */
 
  if (PcOnSq(From(move)) != ((wtm) ? Piece(move) : -Piece(move)))
 
    return 0;
 
  switch (Piece(move)) {
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Null-moves are caught as it is possible for a killer    *
 
 *  move entry to be zero at certain times.                 *
 
 *                                                          *
 
 ************************************************************
 
 */
 
    case empty:
 
      return 0;
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  King moves are validated here if the king is moving two *
 
 *  squares at one time (castling moves).  Otherwise fall   *
 
 *  into the normal piece validation routine below.  For    *
 
 *  castling moves, we need to verify that the castling     *
 
 *  status is correct to avoid "creating" a new rook or     *
 
 *  king.                                                   *
 
 *                                                          *
 
 ************************************************************
 
 */
 
    case king:
 
      if (Abs(From(move) - To(move)) == 2) {
 
        if (Castle(ply, wtm) > 0) {
 
          if (To(move) == csq[wtm]) {
 
            if ((!(Castle(ply, wtm) & 2)) || (OccupiedSquares & OOO[wtm])
 
                || (AttacksTo(tree, csq[wtm]) & Occupied(btm))
 
                || (AttacksTo(tree, dsq[wtm]) & Occupied(btm))
 
                || (AttacksTo(tree, esq[wtm]) & Occupied(btm)))
 
              return 0;
 
          } else if (To(move) == gsq[wtm]) {
 
            if ((!(Castle(ply, wtm) & 1)) || (OccupiedSquares & OO[wtm])
 
                || (AttacksTo(tree, esq[wtm]) & Occupied(btm))
 
                || (AttacksTo(tree, fsq[wtm]) & Occupied(btm))
 
                || (AttacksTo(tree, gsq[wtm]) & Occupied(btm)))
 
              return 0;
 
          }
 
        } else
 
          return 0;
 
        return 1;
 
      }
 
      break;
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Check for a normal pawn advance.                        *
 
 *                                                          *
 
 ************************************************************
 
 */
 
    case pawn:
 
      if (((wtm) ? To(move) - From(move) : From(move) - To(move)) < 0)
 
        return 0;
 
      if (Abs(From(move) - To(move)) == 8)
 
        return (PcOnSq(To(move))) ? 0 : 1;
 
      if (Abs(From(move) - To(move)) == 16)
 
        return (PcOnSq(To(move)) || PcOnSq(To(move) + epdir[wtm])) ? 0 : 1;
 
      if (!Captured(move))
 
        return 0;
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Check for an en passant capture which is somewhat       *
 
 *  unusual in that the [to] square does not contain the    *
 
 *  pawn being captured.  Make sure that the pawn being     *
 
 *  captured advanced two ranks the previous move.          *
 
 *                                                          *
 
 ************************************************************
 
 */
 
      if ((PcOnSq(To(move)) == 0)
 
          && (PcOnSq(To(move) + epdir[wtm]) == ((wtm) ? -pawn : pawn))
 
          && (EnPassantTarget(ply) & SetMask(To(move))))
 
        return 1;
 
      break;
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Normal moves are all checked the same way.              *
 
 *                                                          *
 
 ************************************************************
 
 */
 
    case queen:
 
    case rook:
 
    case bishop:
 
      if (Attack(From(move), To(move)))
 
        break;
 
      return 0;
 
    case knight:
 
      break;
 
  }
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  All normal moves are validated in the same manner, by   *
 
 *  checking the from and to squares and also the attack    *
 
 *  status for completeness.                                *
 
 *                                                          *
 
 ************************************************************
 
 */
 
  return ((Captured(move) == ((wtm) ? -PcOnSq(To(move)) : PcOnSq(To(move))))
 
      && Captured(move) != king) ? 1 : 0;
 
}
 
 
 
/* last modified 02/26/14 */
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   VerifyMove() tests a move to confirm it is absolutely legal. It shouldn't *
 
 *   be used inside the search, but can be used to check a 21-bit (compressed) *
 
 *   move to be sure it is safe to make it on the permanent game board.        *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
int VerifyMove(TREE * RESTRICT tree, int ply, int wtm, int move) {
 
  unsigned moves[256], *mv, *mvp;
 
 
 
/*
 
 Generate moves, then eliminate any that are illegal.
 
 */
 
  if (move == 0)
 
    return 0;
 
  tree->status[MAXPLY] = tree->status[ply];
 
  mvp = GenerateCaptures(tree, MAXPLY, wtm, moves);
 
  mvp = GenerateNoncaptures(tree, MAXPLY, wtm, mvp);
 
  for (mv = &moves[0]; mv < mvp; mv++) {
 
    MakeMove(tree, MAXPLY, wtm, *mv);
 
    if (!Check(wtm) && move == *mv) {
 
      UnmakeMove(tree, MAXPLY, wtm, *mv);
 
      return 1;
 
    }
 
    UnmakeMove(tree, MAXPLY, wtm, *mv);
 
  }
 
  return 0;
 
}
 
 
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   Windows NUMA support                                                      *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
#if !defined(UNIX)
 
static BOOL(WINAPI * pGetNumaHighestNodeNumber) (PULONG);
 
static BOOL(WINAPI * pGetNumaNodeProcessorMask) (UCHAR, PULONGLONG);
 
static DWORD(WINAPI * pSetThreadIdealProcessor) (HANDLE, DWORD);
 
static volatile BOOL fThreadsInitialized = FALSE;
 
static BOOL fSystemIsNUMA = FALSE;
 
static ULONGLONG ullProcessorMask[256];
 
static ULONG ulNumaNodes;
 
static ULONG ulNumaNode = 0;
 
 
 
// Get NUMA-related information from Windows
 
static void WinNumaInit(void) {
 
  //DWORD_PTR dwMask; // Pierre-Marie Baty -- unreferenced variable
 
  HMODULE hModule;
 
  ULONG ulCPU, ulNode;
 
  ULONGLONG ullMask;
 
  DWORD dwCPU;
 
 
 
  if (!fThreadsInitialized) {
 
    Lock(lock_smp);
 
    if (!fThreadsInitialized) {
 
      printf("\nInitializing multiple threads.\n");  
      fThreadsInitialized = TRUE;
 
      hModule = GetModuleHandle("kernel32");
 
      pGetNumaHighestNodeNumber =
 
          (void *) GetProcAddress(hModule, "GetNumaHighestNodeNumber");
 
      pGetNumaNodeProcessorMask =
 
          (void *) GetProcAddress(hModule, "GetNumaNodeProcessorMask");
 
      pSetThreadIdealProcessor =
 
          (void *) GetProcAddress(hModule, "SetThreadIdealProcessor");
 
      if (pGetNumaHighestNodeNumber && pGetNumaNodeProcessorMask &&
 
          pGetNumaHighestNodeNumber(&ulNumaNodes) && (ulNumaNodes > 0)) {
 
        fSystemIsNUMA = TRUE;
 
        if (ulNumaNodes > 255)
 
          ulNumaNodes = 255;
 
        printf("System is NUMA. %d nodes reported by Windows\n",  
            ulNumaNodes + 1);
 
        for (ulNode = 0; ulNode <= ulNumaNodes; ulNode++) {
 
          pGetNumaNodeProcessorMask((UCHAR) ulNode,
 
              &ullProcessorMask[ulNode]);
 
          printf("Node %d CPUs: ", ulNode
);  
          ullMask = ullProcessorMask[ulNode];
 
          if (0 == ullMask)
 
            fSystemIsNUMA = FALSE;
 
          else {
 
            ulCPU = 0;
 
            do {
 
              if (ullMask & 1)
 
              ulCPU++;
 
              ullMask >>= 1;
 
            } while (ullMask);
 
          }
 
        }
 
// Thread 0 was already started on some CPU. To simplify things further,
 
// exchange ullProcessorMask[0] and ullProcessorMask[node for that CPU],
 
// so ullProcessorMask[0] would always be node for thread 0
 
        dwCPU =
 
            pSetThreadIdealProcessor(GetCurrentThread(), MAXIMUM_PROCESSORS);
 
        printf("Current ideal CPU is %u\n", dwCPU
);  
        pSetThreadIdealProcessor(GetCurrentThread(), dwCPU);
 
        if ((((DWORD) - 1) != dwCPU) && (MAXIMUM_PROCESSORS != dwCPU)
 
            && !(ullProcessorMask[0] & (1uLL << dwCPU))) { // Pierre-Marie Baty -- added type cast
 
          for (ulNode = 1; ulNode <= ulNumaNodes; ulNode++) {
 
            if (ullProcessorMask[ulNode] & (1uLL << dwCPU)) { // Pierre-Marie Baty -- added type cast
 
              printf("Exchanging nodes 0 and %d\n", ulNode
);  
              ullMask = ullProcessorMask[ulNode];
 
              ullProcessorMask[ulNode] = ullProcessorMask[0];
 
              ullProcessorMask[0] = ullMask;
 
              break;
 
            }
 
          }
 
        }
 
      } else
 
        printf("System is SMP, not NUMA.\n");  
    }
 
    Unlock(lock_smp);
 
  }
 
}
 
 
 
// Start thread. For NUMA system set its affinity.
 
#  if (CPUS > 1)
 
pthread_t NumaStartThread(void *func, void *args) {
 
  HANDLE hThread;
 
  ULONGLONG ullMask;
 
 
 
  WinNumaInit();
 
  if (fSystemIsNUMA) {
 
    ulNumaNode++;
 
    if (ulNumaNode > ulNumaNodes)
 
      ulNumaNode = 0;
 
    ullMask = ullProcessorMask[ulNumaNode];
 
    printf("Starting thread on node %d CPU mask %I64d\n", ulNumaNode
,  
        ullMask);
 
    SetThreadAffinityMask(GetCurrentThread(), (DWORD_PTR) ullMask);
 
    hThread = (HANDLE) _beginthreadex(0, 0, func, args, CREATE_SUSPENDED, 0);
 
    SetThreadAffinityMask(hThread, (DWORD_PTR) ullMask);
 
    ResumeThread(hThread);
 
    SetThreadAffinityMask(GetCurrentThread(), (DWORD_PTR) ullProcessorMask[0]); // Pierre-Marie Baty -- added type cast
 
  } else
 
    hThread = (HANDLE) _beginthreadex(0, 0, func, args, 0, 0);
 
  return hThread;
 
}
 
#  endif
 
 
 
// Allocate memory for thread #N
 
void *WinMalloc(size_t cbBytes, int iThread) {
 
  HANDLE hThread;
 
  DWORD_PTR dwAffinityMask;
 
  void *pBytes;
 
  ULONG ulNode;
 
 
 
  WinNumaInit();
 
  if (fSystemIsNUMA) {
 
    ulNode = iThread % (ulNumaNodes + 1);
 
    hThread = GetCurrentThread();
 
    dwAffinityMask = SetThreadAffinityMask(hThread, (DWORD_PTR) ullProcessorMask[ulNode]); // Pierre-Marie Baty -- added type cast
 
    pBytes = VirtualAlloc(NULL, cbBytes, MEM_COMMIT, PAGE_READWRITE);
 
    if (pBytes == NULL)
 
      ExitProcess(GetLastError());
 
    SetThreadAffinityMask(hThread, dwAffinityMask);
 
  } else {
 
    pBytes = VirtualAlloc(NULL, cbBytes, MEM_COMMIT, PAGE_READWRITE);
 
    if (pBytes == NULL)
 
      ExitProcess(GetLastError());
 
  }
 
  return pBytes;
 
}
 
 
 
// Allocate interleaved memory
 
void *WinMallocInterleaved(size_t cbBytes, int cThreads) {
 
  char *pBase;
 
  char *pEnd;
 
  char *pch;
 
  HANDLE hThread;
 
  DWORD_PTR dwAffinityMask;
 
  ULONG ulNode;
 
  SYSTEM_INFO sSysInfo;
 
  size_t dwStep;
 
  int iThread;
 
  DWORD dwPageSize;             // the page size on this computer
 
  LPVOID lpvResult;
 
 
 
  WinNumaInit();
 
  if (fSystemIsNUMA && (cThreads > 1)) {
 
    GetSystemInfo(&sSysInfo); // populate the system information structure
 
    dwPageSize = sSysInfo.dwPageSize;
 
// Reserve pages in the process's virtual address space.
 
    pBase = (char *) VirtualAlloc(NULL, cbBytes, MEM_RESERVE, PAGE_NOACCESS);
 
    if (pBase == NULL) {
 
      printf("VirtualAlloc() reserve failed\n");  
      CraftyExit(0);
 
    }
 
// Now walk through memory, committing each page
 
    hThread = GetCurrentThread();
 
    dwStep = dwPageSize * cThreads;
 
    pEnd = pBase + cbBytes;
 
    for (iThread = 0; iThread < cThreads; iThread++) {
 
      ulNode = iThread % (ulNumaNodes + 1);
 
      dwAffinityMask =
 
          SetThreadAffinityMask(hThread, (DWORD_PTR) ullProcessorMask[ulNode]); // Pierre-Marie Baty -- added type cast
 
      for (pch = pBase + iThread * dwPageSize; pch < pEnd; pch += dwStep) {
 
        lpvResult = VirtualAlloc(pch, // next page to commit
 
            dwPageSize, // page size, in bytes
 
            MEM_COMMIT, // allocate a committed page
 
            PAGE_READWRITE); // read/write access
 
        if (lpvResult == NULL)
 
          ExitProcess(GetLastError());
 
        memset(lpvResult
, 0, dwPageSize
);  
      }
 
      SetThreadAffinityMask(hThread, dwAffinityMask);
 
    }
 
  } else {
 
    pBase = VirtualAlloc(NULL, cbBytes, MEM_COMMIT, PAGE_READWRITE);
 
    if (pBase == NULL)
 
      ExitProcess(GetLastError());
 
  }
 
  return (void *) pBase;
 
}
 
 
 
// Free interleaved memory
 
void WinFreeInterleaved(void *pMemory, size_t cBytes) {
 
  VirtualFree(pMemory, 0, MEM_RELEASE);
 
}
 
#endif