Subversion Repositories Games.Chess Giants

Rev

Rev 108 | Go to most recent revision | Details | Last modification | View Log | RSS feed

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