Subversion Repositories Games.Chess Giants

Rev

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