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