Subversion Repositories Games.Chess Giants

Rev

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