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