Subversion Repositories Games.Chess Giants

Rev

Rev 33 | Rev 154 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
33 pmbaty 1
#include <ctype.h>
2
#include <signal.h>
3
#include "chess.h"
4
#include "data.h"
5
#if defined(UNIX)
6
#  include <unistd.h>
7
#  include <signal.h>
8
#endif
9
#include "epdglue.h"
108 pmbaty 10
/* last modified 01/16/15 */
33 pmbaty 11
/*
12
 *******************************************************************************
13
 *                                                                             *
14
 *   Option() is used to handle user input necessary to control/customize the  *
15
 *   program.  It performs all functions excepting chess move input which is   *
16
 *   handled by main().                                                        *
17
 *                                                                             *
18
 *******************************************************************************
19
 */
20
int Option(TREE * RESTRICT tree) {
108 pmbaty 21
  int v;
22
 
33 pmbaty 23
/*
24
 ************************************************************
25
 *                                                          *
26
 *  parse the input.  If it looks like a FEN string, don't  *
27
 *  parse using "/" as a separator, otherwise do.           *
28
 *                                                          *
29
 ************************************************************
30
 */
31
  if (StrCnt(buffer, '/') >= 7)
32
    nargs = ReadParse(buffer, args, " \t;=");
33
  else
34
    nargs = ReadParse(buffer, args, " \t;=/");
35
  if (!nargs)
36
    return 1;
37
  if (args[0][0] == '#')
38
    return 1;
39
/*
40
 ************************************************************
41
 *                                                          *
42
 *  EPD implementation interface code.  EPD commands can    *
43
 *  not be handled if the program is actually searching in  *
44
 *  a real game, and if Crafty is "pondering" this has to   *
45
 *  be stopped.                                             *
46
 *                                                          *
47
 ************************************************************
48
 */
49
#if defined(EPD)
50
  if (initialized) {
51
    if (EGCommandCheck(buffer)) {
52
      if (thinking || pondering)
53
        return 2;
54
      else {
108 pmbaty 55
        EGCommand(buffer);
33 pmbaty 56
        return 1;
57
      }
58
    }
59
  }
60
#endif
61
/*
62
 ************************************************************
63
 *                                                          *
64
 *  "!" character is a 'shell escape' that passes the rest  *
65
 *  of the command to a shell for execution.  Note that it  *
66
 *  is ignored if in xboard mode because one could use your *
67
 *  zippy2password to execute commands on your local        *
68
 *  machine, probably something that is not wanted.         *
69
 *                                                          *
70
 ************************************************************
71
 */
72
  if (buffer[0] == '!') {
108 pmbaty 73
    if (!xboard) {
74
      v = system(strchr(buffer, '!') + 1);
75
      if (v != 0)
76
        perror("Option() system() error: ");
77
    }
33 pmbaty 78
  }
79
/*
80
 ************************************************************
81
 *                                                          *
82
 *  "." ignores "." if it happens to get to this point, if  *
83
 *  xboard is running.                                      *
84
 *                                                          *
85
 ************************************************************
86
 */
87
  else if (OptionMatch(".", *args)) {
88
    if (xboard) {
89
      printf("stat01: 0 0 0 0 0\n");
90
      fflush(stdout);
91
      return 1;
92
    } else
93
      return 0;
94
  }
95
/*
96
 ************************************************************
97
 *                                                          *
98
 *  "accepted" handles the new xboard protocol version 2    *
99
 *  accepted command.                                       *
100
 *                                                          *
101
 ************************************************************
102
 */
103
  else if (OptionMatch("accepted", *args)) {
104
  }
105
/*
106
 ************************************************************
107
 *                                                          *
108
 *  "adaptive" sets the new adaptive hash algorithm         *
109
 *  parameters.  It requires five parameters.  The first is *
110
 *  an estimated NPS, the second is the minimum hash size,  *
111
 *  and the third is the maximum hash size.  The adaptive   *
112
 *  algorithm will look at the time control, and try to     *
113
 *  adjust the hash sizes to an optimal value without       *
114
 *  dropping below the minimum or exceeding the maximum     *
115
 *  memory size given.  The min/max sizes can be given      *
116
 *  using the same syntax as the hash= command, ie xxx,     *
117
 *  xxxK or xxxM will all work. The fourth and fifth        *
118
 *  parameters are used to limit hashp in the same way.     *
119
 *                                                          *
120
 ************************************************************
121
 */
122
  else if (OptionMatch("adaptive", *args)) {
123
    if (nargs != 6) {
124
      printf("usage:  adaptive NPS hmin hmax pmin pmax\n");
125
      return 1;
126
    }
127
    if (nargs > 1) {
108 pmbaty 128
      adaptive_hash = (int) atoiKMB(args[1]); // Pierre-Marie Baty -- added type cast
129
      adaptive_hash_min = (size_t) atoiKMB(args[2]); // Pierre-Marie Baty -- added type cast
130
      adaptive_hash_max = (size_t) atoiKMB(args[3]); // Pierre-Marie Baty -- added type cast
131
      adaptive_hashp_min = (size_t) atoiKMB(args[4]); // Pierre-Marie Baty -- added type cast
132
      adaptive_hashp_max = (size_t) atoiKMB(args[5]); // Pierre-Marie Baty -- added type cast
33 pmbaty 133
    }
108 pmbaty 134
    Print(32, "adaptive estimated NPS =  %s\n", DisplayKMB(adaptive_hash, 1));
135
    Print(32, "adaptive minimum hsize =  %s\n", DisplayKMB(adaptive_hash_min,
33 pmbaty 136
            1));
108 pmbaty 137
    Print(32, "adaptive maximum hsize =  %s\n", DisplayKMB(adaptive_hash_max,
33 pmbaty 138
            1));
108 pmbaty 139
    Print(32, "adaptive minimum psize =  %s\n", DisplayKMB(adaptive_hashp_min,
33 pmbaty 140
            1));
108 pmbaty 141
    Print(32, "adaptive maximum psize =  %s\n", DisplayKMB(adaptive_hashp_max,
33 pmbaty 142
            1));
143
  }
144
/*
145
 ************************************************************
146
 *                                                          *
147
 *  "alarm" command turns audible move warning on/off.      *
148
 *                                                          *
149
 ************************************************************
150
 */
151
  else if (OptionMatch("alarm", *args)) {
152
    if (!strcmp(args[1], "on"))
153
      audible_alarm = 0x07;
154
    else if (!strcmp(args[1], "off"))
155
      audible_alarm = 0x00;
156
    else
157
      printf("usage:  alarm on|off\n");
158
  }
159
/*
160
 ************************************************************
161
 *                                                          *
162
 *  "analyze" puts Crafty in analyze mode, where it reads   *
163
 *  moves in and between moves, computes as though it is    *
164
 *  trying to find the best move to make.  When another     *
165
 *  move is entered, it switches sides and continues.  It   *
166
 *  will never make a move on its own, rather, it will      *
167
 *  continue to analyze until an "exit" command is given.   *
168
 *                                                          *
169
 ************************************************************
170
 */
171
  else if (OptionMatch("analyze", *args)) {
172
    if (thinking || pondering)
173
      return 2;
174
    Analyze();
175
  }
176
/*
177
 ************************************************************
178
 *                                                          *
179
 *  "annotate" command is used to read a series of moves    *
180
 *  and analyze the resulting game, producing comments as   *
181
 *  requested by the user.  This also handles the annotateh *
182
 *  (html) and annotatet (LaTex) output forms of the        *
183
 *  command.                                                *
184
 *                                                          *
185
 ************************************************************
186
 */
187
  else if (OptionMatch("annotate", *args) || OptionMatch("annotateh", *args)
188
      || OptionMatch("annotatet", *args)) {
189
    if (thinking || pondering)
190
      return 2;
191
    Annotate();
192
  }
193
/*
194
 ************************************************************
195
 *                                                          *
108 pmbaty 196
 *  "autotune" command is used to automatically tune the    *
197
 *  SMP search parameters that affect search efficiency.    *
198
 *                                                          *
199
 ************************************************************
200
 */
201
  else if (OptionMatch("autotune", *args)) {
202
    if (thinking || pondering)
203
      return 2;
204
    AutoTune(nargs, args);
205
  }
206
/*
207
 ************************************************************
208
 *                                                          *
33 pmbaty 209
 *  "batch" command disables asynchronous I/O so that a     *
210
 *  stream of commands can be put into a file and they are  *
211
 *  not executed instantly.                                 *
212
 *                                                          *
213
 ************************************************************
214
 */
215
  else if (OptionMatch("batch", *args)) {
216
    if (!strcmp(args[1], "on"))
217
      batch_mode = 1;
218
    else if (!strcmp(args[1], "off"))
219
      batch_mode = 0;
220
    else
221
      printf("usage:  batch on|off\n");
222
  }
223
/*
224
 ************************************************************
225
 *                                                          *
226
 *  "beep" command is ignored. [xboard compatibility]       *
227
 *                                                          *
228
 ************************************************************
229
 */
230
  else if (OptionMatch("beep", *args)) {
231
    return xboard;
232
  }
233
/*
234
 ************************************************************
235
 *                                                          *
108 pmbaty 236
 *  "bench" runs internal performance benchmark.  An        *
237
 *  optional second argument can increase or decrease the   *
238
 *  time it takes.  "bench 1" increases the default depth   *
239
 *  by one ply, and "bench -1" reduces the depth to speed   *
240
 *  it up.                                                  *
33 pmbaty 241
 *                                                          *
242
 ************************************************************
243
 */
244
  else if (OptionMatch("bench", *args)) {
108 pmbaty 245
    int mod = 0, time;
246
 
247
    if (nargs > 1)
248
      mod = atoi(args[1]);
249
    time = Bench(mod, 0);
250
    Print(32, "time used = %s\n", DisplayTime(time));
33 pmbaty 251
  }
252
/*
108 pmbaty 253
 ***************************************************************
254
 *                                                             *
255
 *  "pgo" runs an internal performance benchmark used for PGO. *
256
 *  An optional second argument can increase or decrease       *
257
 *  the time it takes.  "pgo 1" increases the default          *
258
 *  by one ply, and "pgo -1" reduces the depth to speed        *
259
 *  it up.                                                     *
260
 *                                                             *
33 pmbaty 261
 ************************************************************
108 pmbaty 262
         */
263
  else if (OptionMatch("pgo", *args)) {
264
    int mod = 0, time;
265
 
266
    if (nargs > 1)
267
      mod = atoi(args[1]);
268
    time = Bench_PGO(mod, 0);
269
    Print(32, "time used = %s\n", DisplayTime(time));
270
  }
271
/*
272
 ************************************************************
33 pmbaty 273
 *                                                          *
274
 *  "bk"  book command from xboard sends the suggested book *
275
 *  moves.                                                  *
276
 *                                                          *
277
 ************************************************************
278
 */
279
  else if (OptionMatch("bk", *args)) {
280
    printf("\t%s\n\n", book_hint);
281
    fflush(stdout);
282
    return xboard;
283
  }
284
/*
285
 ************************************************************
286
 *                                                          *
287
 *  "black" command sets black to move (Flip(wtm)).         *
288
 *                                                          *
289
 ************************************************************
290
 */
108 pmbaty 291
  else if (OptionMatch("white", *args)) {
33 pmbaty 292
    if (thinking || pondering)
293
      return 2;
108 pmbaty 294
    game_wtm = 1;
33 pmbaty 295
    ponder_move = 0;
296
    last_pv.pathd = 0;
297
    last_pv.pathl = 0;
298
    if (!game_wtm)
299
      Pass();
300
    force = 0;
108 pmbaty 301
  } else if (OptionMatch("black", *args)) {
33 pmbaty 302
    if (thinking || pondering)
303
      return 2;
108 pmbaty 304
    game_wtm = 0;
33 pmbaty 305
    ponder_move = 0;
306
    last_pv.pathd = 0;
307
    last_pv.pathl = 0;
308
    if (game_wtm)
309
      Pass();
310
    force = 0;
311
  }
312
/*
313
 ************************************************************
314
 *                                                          *
315
 *  "bogus" command is ignored. [xboard compatibility]      *
316
 *                                                          *
317
 ************************************************************
318
 */
319
  else if (OptionMatch("bogus", *args)) {
320
    return xboard;
321
  }
322
/*
323
 ************************************************************
324
 *                                                          *
108 pmbaty 325
 *  "book" command updates/creates the opening book file.   *
326
 *                                                          *
327
 ************************************************************
328
 */
329
  else if (OptionMatch("book", *args)) {
330
    nargs = ReadParse(buffer, args, " \t;");
331
    Bookup(tree, nargs, args);
332
  } else if (!strcmp("create", *(args + 1))) {
333
    nargs = ReadParse(buffer, args, " \t;");
334
    Bookup(tree, nargs, args);
335
  }
336
/*
337
 ************************************************************
338
 *                                                          *
33 pmbaty 339
 *  "bookw" command updates the book selection weights.     *
340
 *                                                          *
341
 ************************************************************
342
 */
108 pmbaty 343
  else if (OptionMatch("bookw", *args)) {
33 pmbaty 344
    if (nargs > 1) {
108 pmbaty 345
      if (OptionMatch("frequency", args[1]))
33 pmbaty 346
        book_weight_freq = (float) atof(args[2]); // Pierre-Marie Baty -- added type cast
108 pmbaty 347
      else if (OptionMatch("evaluation", args[1]))
33 pmbaty 348
        book_weight_eval = (float) atof(args[2]); // Pierre-Marie Baty -- added type cast
108 pmbaty 349
      else if (OptionMatch("learning", args[1]))
33 pmbaty 350
        book_weight_learn = (float) atof(args[2]); // Pierre-Marie Baty -- added type cast
351
    } else {
108 pmbaty 352
      Print(32, "frequency (freq)..............%4.2f\n", book_weight_freq);
353
      Print(32, "static evaluation (eval)......%4.2f\n", book_weight_eval);
354
      Print(32, "learning (learn)..............%4.2f\n", book_weight_learn);
33 pmbaty 355
    }
356
  }
357
/*
358
 ************************************************************
359
 *                                                          *
360
 *  "cache" is used to set the EGTB cache size.  As always  *
361
 *  bigger is better.  The default is 1mb.  Sizes can be    *
362
 *  specified in bytes, Kbytes or Mbytes as with the hash   *
363
 *  commands.                                               *
364
 *                                                          *
365
 ************************************************************
366
 */
367
#if !defined(NOEGTB)
368
  else if (OptionMatch("cache", *args)) {
108 pmbaty 369
    EGTB_cache_size = (size_t) atoiKMB(args[1]); // Pierre-Marie Baty -- added type cast
33 pmbaty 370
    if (EGTB_cache)
371
      free(EGTB_cache);
372
    EGTB_cache = malloc(EGTB_cache_size);
373
    if (!EGTB_cache) {
374
      Print(2095,
375
          "ERROR:  unable to malloc specified cache size, using default\n");
376
      EGTB_cache = malloc(4096 * 4096);
377
    }
108 pmbaty 378
    Print(32, "EGTB cache memory = %s bytes.\n", DisplayKMB(EGTB_cache_size,
33 pmbaty 379
            1));
380
    FTbSetCacheSize(EGTB_cache, EGTB_cache_size);
381
  }
382
#endif
383
/*
384
 ************************************************************
385
 *                                                          *
386
 *  "clock" command displays chess clock.                   *
387
 *                                                          *
388
 ************************************************************
389
 */
390
  else if (OptionMatch("clock", *args)) {
391
    int side;
392
 
393
    for (side = white; side >= black; side--) {
108 pmbaty 394
      Print(32, "time remaining (%s): %s", (side) ? "white" : "black",
33 pmbaty 395
          DisplayHHMMSS(tc_time_remaining[side]));
396
      if (tc_sudden_death != 1)
108 pmbaty 397
        Print(32, "  (%d more moves)", tc_moves_remaining[side]);
398
      Print(32, "\n");
33 pmbaty 399
    }
108 pmbaty 400
    Print(32, "\n");
33 pmbaty 401
    if (tc_sudden_death == 1)
108 pmbaty 402
      Print(32, "Sudden-death time control in effect\n");
33 pmbaty 403
  }
404
/*
405
 ************************************************************
406
 *                                                          *
407
 *  "computer" lets Crafty know it is playing a computer.   *
408
 *                                                          *
409
 ************************************************************
410
 */
411
  else if (OptionMatch("computer", *args)) {
108 pmbaty 412
    Print(32, "playing a computer!\n");
33 pmbaty 413
    accept_draws = 1;
108 pmbaty 414
    if (resign)
415
      resign = 10;
416
    resign_count = 4;
33 pmbaty 417
    usage_level = 0;
418
    books_file = (computer_bs_file) ? computer_bs_file : normal_bs_file;
419
  }
420
/*
421
 ************************************************************
422
 *                                                          *
423
 *  "display" command displays the chess board.             *
424
 *                                                          *
425
 *  "display" command sets specific display options which   *
426
 *  control how "chatty" the program is.  In the variable   *
427
 *  display_options, the following bits are set/cleared     *
428
 *  based on the option chosen.                             *
429
 *                                                          *
108 pmbaty 430
 *    1 -> display move/time/results/etc.                   *
431
 *    2 -> display PV.                                      *
432
 *    4 -> display fail high / fail low moves               *
433
 *    8 -> display search statistics.                       *
434
 *   16 -> display root moves as they are searched.         *
435
 *   32 -> display general informational messages.          *
436
 *   64 -> display ply-1 move list / flags after each       *
33 pmbaty 437
 *         iteration.                                       *
108 pmbaty 438
 *  128 -> display root moves and scores before search      *
439
 *         begins.                                          *
440
 * 2048 -> error messages (can not be disabled).            *
33 pmbaty 441
 *                                                          *
442
 ************************************************************
443
 */
444
  else if (OptionMatch("display", *args)) {
108 pmbaty 445
    int i, set, old_display_options = display_options;
446
    char *doptions[8] = { "moveinfo", "pv", "fail", "stats", "moves", "info",
447
      "ply1", "movelist"
448
    };
449
    char *descriptions[8] = { "display move time/results/etc",
450
      "principal variation", "fail highs/lows", "search statistics",
451
      "root moves as they are searched", "general information",
452
      "ply1 move list after each iteration",
453
      "root move list and scores prior to search"
454
    };
455
 
456
    if (nargs > 1) {
457
      if (!strcmp(args[1], "all"))
458
        old_display_options = ~display_options;
459
      for (i = 0; i < 8; i++) {
460
        if (strstr(args[1], doptions[i])) {
461
          if (strstr(args[1], "no"))
462
            set = 0;
463
          else
464
            set = 1;
465
          display_options &= ~(1 << i);
466
          display_options |= set << i;
33 pmbaty 467
          break;
108 pmbaty 468
        }
469
      }
470
      for (i = 0; i < 8; i++) {
471
        if ((old_display_options & (1 << i)) != (display_options & (1 << i))) {
472
          Print(32, "display ");
473
          if (!(display_options & (1 << i)))
474
            Print(32, "no");
475
          Print(32, "%s (%s)\n", doptions[i], descriptions[i]);
476
        }
477
      }
478
    } else
33 pmbaty 479
      DisplayChessBoard(stdout, display);
480
  }
481
/*
482
 ************************************************************
483
 *                                                          *
484
 *  "debug" handles the new debug command that is often     *
485
 *  modified to test some modified code function.           *
486
 *                                                          *
487
 ************************************************************
488
 */
489
  else if (OptionMatch("debug", *args)) {
108 pmbaty 490
    Print(32, "ERROR:  no debug code included\n");
33 pmbaty 491
  }
492
/*
493
 ************************************************************
494
 *                                                          *
495
 *  "depth" command sets a specific search depth to         *
496
 *  control the tree search depth. [xboard compatibility].  *
497
 *                                                          *
498
 ************************************************************
499
 */
108 pmbaty 500
  else if (OptionMatch("depth", *args)) {
33 pmbaty 501
    if (nargs < 2) {
502
      printf("usage:  depth <n>\n");
503
      return 1;
504
    }
505
    search_depth = atoi(args[1]);
108 pmbaty 506
    Print(32, "search depth set to %d.\n", search_depth);
33 pmbaty 507
  }
508
/*
509
 ************************************************************
510
 *                                                          *
511
 *  "draw" is used to offer Crafty a draw, or to control    *
512
 *  whether Crafty will offer and/or accept draw offers.    *
513
 *                                                          *
514
 ************************************************************
515
 */
516
  else if (OptionMatch("draw", *args)) {
517
    if (nargs == 1) {
518
      draw_offer_pending = 1;
519
      if (draw_offered) {
520
        Print(4095, "1/2-1/2 {Draw agreed}\n");
108 pmbaty 521
        strcpy(pgn_result, "1/2-1/2");
33 pmbaty 522
      }
523
    } else {
524
      if (!strcmp(args[1], "accept")) {
525
        accept_draws = 1;
108 pmbaty 526
        Print(32, "accept draw offers\n");
33 pmbaty 527
      } else if (!strcmp(args[1], "decline")) {
528
        accept_draws = 0;
108 pmbaty 529
        Print(32, "decline draw offers\n");
530
      } else if (!strcmp(args[1], "dynamic")) {
531
        if (nargs > 2)
532
          dynamic_draw_score = atoi(args[2]);
533
        Print(32, "dynamic draw scores %s\n",
534
            (dynamic_draw_score) ? "enabled" : "disabled");
33 pmbaty 535
      } else if (!strcmp(args[1], "offer")) {
536
        offer_draws = 1;
108 pmbaty 537
        Print(32, "offer draws\n");
33 pmbaty 538
      } else if (!strcmp(args[1], "nooffer")) {
539
        offer_draws = 0;
108 pmbaty 540
        Print(32, "do not offer draws\n");
33 pmbaty 541
      } else
108 pmbaty 542
        Print(32, "usage: draw accept|decline|offer|nooffer\n");
33 pmbaty 543
    }
544
  }
545
/*
546
 ************************************************************
547
 *                                                          *
548
 *  "easy" command disables thinking on opponent's time.    *
549
 *                                                          *
550
 ************************************************************
551
 */
552
  else if (OptionMatch("easy", *args)) {
553
    if (thinking || pondering)
554
      return 2;
555
    ponder = 0;
108 pmbaty 556
    Print(32, "pondering disabled.\n");
33 pmbaty 557
  }
558
/*
559
 ************************************************************
560
 *                                                          *
561
 *  "echo" command displays messages from command file.     *
562
 *                                                          *
563
 ************************************************************
564
 */
565
  else if (OptionMatch("echo", *args) || OptionMatch("title", *args)) {
566
  }
567
/*
568
 ************************************************************
569
 *                                                          *
570
 *  "edit" command modifies the board position.             *
571
 *                                                          *
572
 ************************************************************
573
 */
108 pmbaty 574
  else if (OptionMatch("edit", *args)) {
33 pmbaty 575
    if (thinking || pondering)
576
      return 2;
577
    Edit();
108 pmbaty 578
    move_number = 1; /* discard history */
33 pmbaty 579
    if (!game_wtm) {
580
      game_wtm = 1;
581
      Pass();
582
    }
583
    ponder_move = 0;
584
    last_pv.pathd = 0;
585
    last_pv.pathl = 0;
108 pmbaty 586
    strcpy(buffer, "savepos *");
587
    Option(tree);
33 pmbaty 588
  }
589
/*
590
 ************************************************************
591
 *                                                          *
592
 *  "egtb" command enables/disables tablebases and sets     *
593
 *  the number of pieces available for probing.             *
594
 *                                                          *
595
 ************************************************************
596
 */
597
#if !defined(NOEGTB)
598
  else if (OptionMatch("egtb", *args)) {
599
    if (!EGTB_setup) {
108 pmbaty 600
      Print(32, "EGTB access enabled\n");
601
      Print(32, "using tbpath=%s\n", tb_path);
33 pmbaty 602
      EGTBlimit = IInitializeTb(tb_path);
108 pmbaty 603
      Print(32, "%d piece tablebase files found\n", EGTBlimit);
33 pmbaty 604
      if (0 != cbEGTBCompBytes)
108 pmbaty 605
        Print(32,
33 pmbaty 606
            "%dkb of RAM used for TB indices and decompression tables\n",
607
            (cbEGTBCompBytes + 1023) / 1024);
608
      if (EGTBlimit) {
609
        if (!EGTB_cache)
610
          EGTB_cache = malloc(EGTB_cache_size);
611
        if (!EGTB_cache) {
108 pmbaty 612
          Print(32, "ERROR  EGTB cache malloc failed\n");
33 pmbaty 613
          EGTB_cache = malloc(4096 * 4096);
614
        } else
615
          FTbSetCacheSize(EGTB_cache, EGTB_cache_size);
616
        EGTB_setup = 1;
617
      }
618
    } else {
619
      if (nargs == 1)
620
        EGTBPV(tree, game_wtm);
621
      else if (nargs == 2)
622
        EGTBlimit = Min(atoi(args[1]), 5);
623
    }
624
  }
108 pmbaty 625
/*
626
 ************************************************************
627
 *                                                          *
628
 *  "egtbd" command sets the probe depth limit.  If the     *
629
 *  remaining depth is < this limit, probes are not done to *
630
 *  avoid slowing the search unnecessarily.                 *
631
 *                                                          *
632
 ************************************************************
633
 */
634
  else if (OptionMatch("egtbd", *args)) {
635
    if (nargs > 1)
636
      EGTB_depth = atoi(args[1]);
637
    Print(32, "EGTB probe depth set to %d\n", EGTB_depth);
638
  }
33 pmbaty 639
#endif
640
/*
641
 ************************************************************
642
 *                                                          *
643
 *  "end" (or "quit") command terminates the program.       *
644
 *                                                          *
645
 ************************************************************
646
 */
647
  else if (OptionMatch("end", *args) || OptionMatch("quit", *args)) {
648
    abort_search = 1;
649
    quit = 1;
650
    last_search_value =
651
        (crafty_is_white) ? last_search_value : -last_search_value;
652
    if (moves_out_of_book)
653
      LearnBook();
654
    if (thinking || pondering)
655
      return 1;
656
    CraftyExit(0);
657
  }
658
/*
659
 ************************************************************
660
 *                                                          *
661
 *  "evtest" command runs a test suite of problems and      *
662
 *  prints evaluations only.                                *
663
 *                                                          *
664
 ************************************************************
665
 */
666
  else if (OptionMatch("evtest", *args)) {
667
    if (thinking || pondering)
668
      return 2;
669
    if (nargs < 2) {
670
      printf("usage:  evtest <filename>\n");
671
      return 1;
672
    }
673
    EVTest(args[1]);
674
    ponder_move = 0;
675
    last_pv.pathd = 0;
676
    last_pv.pathl = 0;
677
  }
678
/*
679
 ************************************************************
680
 *                                                          *
681
 *  "exit" command resets input device to STDIN.            *
682
 *                                                          *
683
 ************************************************************
684
 */
685
  else if (OptionMatch("exit", *args)) {
686
    if (analyze_mode)
687
      return 0;
688
    if (input_stream != stdin)
689
      fclose(input_stream);
690
    input_stream = stdin;
691
    ReadClear();
108 pmbaty 692
    Print(32, "\n");
33 pmbaty 693
  }
694
/*
695
 ************************************************************
696
 *                                                          *
697
 *  "flag" command controls whether Crafty will call the    *
698
 *  flag in xboard/winboard games (to end the game.)        *
699
 *                                                          *
700
 ************************************************************
701
 */
108 pmbaty 702
  else if (OptionMatch("flag", *args)) {
33 pmbaty 703
    if (nargs < 2) {
704
      printf("usage:  flag on|off\n");
705
      return 1;
706
    }
707
    if (!strcmp(args[1], "on"))
708
      call_flag = 1;
709
    else if (!strcmp(args[1], "off"))
710
      call_flag = 0;
711
    if (call_flag)
108 pmbaty 712
      Print(32, "end game on time forfeits\n");
33 pmbaty 713
    else
108 pmbaty 714
      Print(32, "ignore time forfeits\n");
33 pmbaty 715
  }
716
/*
717
 ************************************************************
718
 *                                                          *
719
 *  "flip" command flips the board, interchanging each      *
720
 *  rank with the corresponding rank on the other half of   *
721
 *  the board, and also reverses the color of all pieces.   *
722
 *                                                          *
723
 ************************************************************
724
 */
725
  else if (OptionMatch("flip", *args)) {
726
    int file, rank, piece, temp;
727
 
728
    if (thinking || pondering)
729
      return 2;
730
    for (rank = 0; rank < 4; rank++) {
731
      for (file = 0; file < 8; file++) {
732
        piece = -PcOnSq((rank << 3) + file);
733
        PcOnSq((rank << 3) + file) = -PcOnSq(((7 - rank) << 3) + file);
734
        PcOnSq(((7 - rank) << 3) + file) = piece;
735
      }
736
    }
737
    game_wtm = Flip(game_wtm);
738
    temp = Castle(0, white);
739
    Castle(0, white) = Castle(0, black);
740
    Castle(0, black) = temp;
741
    SetChessBitBoards(tree);
742
#if defined(DEBUG)
743
    ValidatePosition(tree, 0, game_wtm, "Option().flip");
744
#endif
745
  }
746
/*
747
 ************************************************************
748
 *                                                          *
749
 *  "flop" command flops the board, interchanging each      *
750
 *  file with the corresponding file on the other half of   *
751
 *  the board.                                              *
752
 *                                                          *
753
 ************************************************************
754
 */
755
  else if (OptionMatch("flop", *args)) {
756
    int file, rank, piece;
757
 
758
    if (thinking || pondering)
759
      return 2;
760
    for (rank = 0; rank < 8; rank++) {
761
      for (file = 0; file < 4; file++) {
762
        piece = PcOnSq((rank << 3) + file);
763
        PcOnSq((rank << 3) + file) = PcOnSq((rank << 3) + 7 - file);
764
        PcOnSq((rank << 3) + 7 - file) = piece;
765
      }
766
    }
767
    SetChessBitBoards(tree);
768
#if defined(DEBUG)
769
    ValidatePosition(tree, 0, game_wtm, "Option().flop");
770
#endif
771
  }
772
/*
773
 ************************************************************
774
 *                                                          *
775
 *  "force" command forces the program to make a specific   *
776
 *  move instead of its last chosen move.                   *
777
 *                                                          *
778
 ************************************************************
779
 */
780
  else if (OptionMatch("force", *args)) {
781
    int move, movenum, save_move_number;
782
    char text[16];
783
 
784
    if (thinking || pondering)
785
      return 3;
786
    if (xboard) {
787
      force = 1;
788
      return 3;
789
    }
790
    if (nargs < 2) {
791
      printf("usage:  force <move>\n");
792
      return 1;
793
    }
794
    ponder_move = 0;
795
    presult = 0;
796
    last_pv.pathd = 0;
797
    last_pv.pathl = 0;
798
    save_move_number = move_number;
799
    movenum = move_number;
800
    if (game_wtm)
801
      movenum--;
108 pmbaty 802
    strcpy(text, args[1]);
803
    sprintf(buffer, "reset %d", movenum);
33 pmbaty 804
    game_wtm = Flip(game_wtm);
108 pmbaty 805
    Option(tree);
806
    move = InputMove(tree, 0, game_wtm, 0, 0, text);
33 pmbaty 807
    if (move) {
808
      if (input_stream != stdin)
108 pmbaty 809
        printf("%s\n", OutputMove(tree, 0, game_wtm, move));
33 pmbaty 810
      if (history_file) {
811
        fseek(history_file, ((movenum - 1) * 2 + 1 - game_wtm) * 10,
812
            SEEK_SET);
108 pmbaty 813
        fprintf(history_file, "%9s\n", OutputMove(tree, 0, game_wtm, move));
33 pmbaty 814
      }
108 pmbaty 815
      MakeMoveRoot(tree, game_wtm, move);
33 pmbaty 816
      last_pv.pathd = 0;
817
      last_pv.pathl = 0;
818
    } else if (input_stream == stdin)
819
      printf("illegal move.\n");
820
    game_wtm = Flip(game_wtm);
821
    move_number = save_move_number;
108 pmbaty 822
    strcpy(ponder_text, "none");
33 pmbaty 823
  }
824
/*
825
 ************************************************************
826
 *                                                          *
827
 *  "go" command does nothing, except force main() to start *
828
 *  a search.  ("move" is an alias for go).                 *
829
 *                                                          *
830
 ************************************************************
831
 */
832
  else if (OptionMatch("go", *args) || OptionMatch("move", *args)) {
108 pmbaty 833
    int t;
33 pmbaty 834
    char temp[128];
835
 
836
    if (thinking || pondering)
837
      return 2;
838
    if (game_wtm) {
839
      if (strncmp(pgn_white, "Crafty", 6)) {
108 pmbaty 840
        strcpy(temp, pgn_white);
841
        strcpy(pgn_white, pgn_black);
842
        strcpy(pgn_black, temp);
33 pmbaty 843
      }
844
    } else {
845
      if (strncmp(pgn_black, "Crafty", 6)) {
108 pmbaty 846
        strcpy(temp, pgn_white);
847
        strcpy(pgn_white, pgn_black);
848
        strcpy(pgn_black, temp);
33 pmbaty 849
      }
850
    }
108 pmbaty 851
    t = tc_time_remaining[white];
852
    tc_time_remaining[white] = tc_time_remaining[black];
853
    tc_time_remaining[black] = t;
854
    t = tc_moves_remaining[white];
855
    tc_moves_remaining[white] = tc_moves_remaining[black];
856
    tc_moves_remaining[black] = t;
33 pmbaty 857
    force = 0;
858
    return -1;
859
  }
860
/*
861
 ************************************************************
862
 *                                                          *
863
 *  "history" command displays game history (moves).        *
864
 *                                                          *
865
 ************************************************************
866
 */
867
  else if (OptionMatch("history", *args)) {
868
    int i;
869
    char buffer[128];
870
 
871
    if (history_file) {
872
      printf("    white       black\n");
873
      for (i = 0; i < (move_number - 1) * 2 - game_wtm + 1; i++) {
874
        fseek(history_file, i * 10, SEEK_SET);
108 pmbaty 875
        v = fscanf(history_file, "%s", buffer);
876
        if (v <= 0)
877
          perror("Option() fscanf error: ");
33 pmbaty 878
        if (!(i % 2))
879
          printf("%3d", i / 2 + 1);
880
        printf("  %-10s", buffer);
881
        if (i % 2 == 1)
882
          printf("\n");
883
      }
884
      if (Flip(game_wtm))
885
        printf("  ...\n");
886
    }
887
  }
888
/*
889
 ************************************************************
890
 *                                                          *
891
 *  "hard" command enables thinking on opponent's time.     *
892
 *                                                          *
893
 ************************************************************
894
 */
895
  else if (OptionMatch("hard", *args)) {
896
    ponder = 1;
108 pmbaty 897
    Print(32, "pondering enabled.\n");
33 pmbaty 898
  }
899
/*
900
 ************************************************************
901
 *                                                          *
902
 *  "hash" command controls the transposition table size.   *
108 pmbaty 903
 *  The size can be entered in one of four ways:            *
33 pmbaty 904
 *                                                          *
905
 *     hash=nnn  where nnn is in bytes.                     *
906
 *     hash=nnnK where nnn is in K bytes.                   *
907
 *     hash=nnnM where nnn is in M bytes.                   *
108 pmbaty 908
 *     hash=nnnG where nnn is in G bytes.                   *
33 pmbaty 909
 *                                                          *
910
 *  the only restriction is that the hash table is computed *
911
 *  as a perfect power of 2.  Any value that is not a       *
912
 *  perfect power of 2 is rounded down so that it is, in    *
913
 *  order to avoid breaking the addressing scheme.          *
914
 *                                                          *
915
 ************************************************************
916
 */
917
  else if (OptionMatch("hash", *args)) {
108 pmbaty 918
    size_t old_hash_size = hash_table_size, new_hash_size;
33 pmbaty 919
 
920
    if (thinking || pondering)
921
      return 2;
922
    if (nargs > 1) {
923
      allow_memory = 0;
108 pmbaty 924
      if (xboard)
925
        Print(4095, "Warning--  xboard 'memory' option disabled\n");
926
      new_hash_size = (size_t) atoiKMB(args[1]); // Pierre-Marie Baty -- added type cast
33 pmbaty 927
      if (new_hash_size < 64 * 1024) {
928
        printf("ERROR.  Minimum hash table size is 64K bytes.\n");
929
        return 1;
930
      }
108 pmbaty 931
      hash_table_size = ((1ull) << MSB(new_hash_size)) / 16;
932
      AlignedRemalloc((void *) ((void *) &hash_table), 64,
933
          hash_table_size * sizeof(HASH_ENTRY));
934
      if (!hash_table) {
33 pmbaty 935
        printf("AlignedRemalloc() failed, not enough memory.\n");
936
        exit(1);
937
      }
108 pmbaty 938
      hash_mask = (hash_table_size - 1) & ~3;
33 pmbaty 939
    }
108 pmbaty 940
    Print(32, "hash table memory = %s bytes",
941
        DisplayKMB(hash_table_size * sizeof(HASH_ENTRY), 1));
942
    Print(32, " (%s entries).\n", DisplayKMB(hash_table_size, 1));
943
    InitializeHashTables(old_hash_size != hash_table_size);
33 pmbaty 944
  }
945
/*
946
 ************************************************************
947
 *                                                          *
948
 *  "phash" command controls the path hash table size. The  *
108 pmbaty 949
 *  size can be entered in one of four ways:                *
33 pmbaty 950
 *                                                          *
951
 *     phash=nnn  where nnn is in bytes.                    *
952
 *     phash=nnnK where nnn is in K bytes.                  *
953
 *     phash=nnnM where nnn is in M bytes.                  *
108 pmbaty 954
 *     phash=nnnG where nnn is in G bytes.                  *
33 pmbaty 955
 *                                                          *
956
 *  the only restriction is that the path hash table must   *
957
 *  have a perfect power of 2 entries.  The value entered   *
958
 *  will be rounded down to meet that requirement.          *
959
 *                                                          *
960
 ************************************************************
961
 */
962
  else if (OptionMatch("phash", *args)) {
108 pmbaty 963
    size_t old_hash_size = hash_path_size, new_hash_size;
33 pmbaty 964
 
965
    if (thinking || pondering)
966
      return 2;
967
    if (nargs > 1) {
108 pmbaty 968
      new_hash_size = (size_t) atoiKMB(args[1]); // Pierre-Marie Baty -- added type cast
33 pmbaty 969
      if (new_hash_size < 64 * 1024) {
970
        printf("ERROR.  Minimum phash table size is 64K bytes.\n");
971
        return 1;
972
      }
973
      hash_path_size = ((1ull) << MSB(new_hash_size / sizeof(HPATH_ENTRY)));
108 pmbaty 974
      AlignedRemalloc((void *) ((void *) &hash_path), 64,
33 pmbaty 975
          sizeof(HPATH_ENTRY) * hash_path_size);
976
      if (!hash_path) {
977
        printf("AlignedRemalloc() failed, not enough memory.\n");
978
        hash_path_size = 0;
979
        hash_path = 0;
980
      }
981
      hash_path_mask = (hash_path_size - 1) & ~15;
982
    }
108 pmbaty 983
    Print(32, "hash path table memory = %s bytes",
984
        DisplayKMB(hash_path_size * sizeof(HPATH_ENTRY), 1));
985
    Print(32, " (%s entries).\n", DisplayKMB(hash_path_size, 1));
986
    InitializeHashTables(old_hash_size != hash_path_size);
33 pmbaty 987
  }
988
/*
989
 ************************************************************
990
 *                                                          *
991
 *  "hashp" command controls the pawn hash table size.      *
992
 *                                                          *
993
 ************************************************************
994
 */
995
  else if (OptionMatch("hashp", *args)) {
108 pmbaty 996
    size_t old_hash_size = pawn_hash_table_size, new_hash_size;
33 pmbaty 997
 
998
    if (thinking || pondering)
999
      return 2;
1000
    if (nargs > 1) {
1001
      allow_memory = 0;
108 pmbaty 1002
      if (xboard)
1003
        Print(4095, "Warning--  xboard 'memory' option disabled\n");
1004
      new_hash_size = (size_t) atoiKMB(args[1]); // Pierre-Marie Baty -- added type cast
33 pmbaty 1005
      if (new_hash_size < 16 * 1024) {
1006
        printf("ERROR.  Minimum pawn hash table size is 16K bytes.\n");
1007
        return 1;
1008
      }
1009
      pawn_hash_table_size =
108 pmbaty 1010
          1ull << MSB(new_hash_size / sizeof(PAWN_HASH_ENTRY));
1011
      AlignedRemalloc((void *) ((void *) &pawn_hash_table), 64,
33 pmbaty 1012
          sizeof(PAWN_HASH_ENTRY) * pawn_hash_table_size);
1013
      if (!pawn_hash_table) {
1014
        printf("AlignedRemalloc() failed, not enough memory.\n");
1015
        exit(1);
1016
      }
108 pmbaty 1017
      pawn_hash_mask = pawn_hash_table_size - 1;
1018
    }
1019
    Print(32, "pawn hash table memory = %s bytes",
1020
        DisplayKMB(pawn_hash_table_size * sizeof(PAWN_HASH_ENTRY), 1));
1021
    Print(32, " (%s entries).\n", DisplayKMB(pawn_hash_table_size, 1));
1022
    InitializeHashTables(old_hash_size != pawn_hash_table_size);
1023
  }
1024
/*
1025
 ************************************************************
1026
 *                                                          *
1027
 *  "hashe" command controls the eval hash table size.      *
1028
 *                                                          *
1029
 ************************************************************
1030
 */
1031
  else if (OptionMatch("hashe", *args)) {
1032
    size_t old_hash_size = eval_hash_table_size, new_hash_size;
1033
 
1034
    if (thinking || pondering)
1035
      return 2;
1036
    if (nargs > 1) {
1037
      allow_memory = 0;
1038
      if (xboard)
1039
        Print(4095, "Warning--  xboard 'memory' option disabled\n");
1040
      new_hash_size = (size_t) atoiKMB(args[1]); // Pierre-Marie Baty -- added type cast
1041
      if (new_hash_size < 16 * 1024) {
1042
        printf("ERROR.  Minimum eval hash table size is 16K bytes.\n");
1043
        return 1;
33 pmbaty 1044
      }
108 pmbaty 1045
      eval_hash_table_size = 1ull << MSB(new_hash_size / sizeof(uint64_t));
1046
      AlignedRemalloc((void *) ((void *) &eval_hash_table), 64,
1047
          sizeof(uint64_t) * eval_hash_table_size);
1048
      if (!eval_hash_table) {
1049
        printf("AlignedRemalloc() failed, not enough memory.\n");
1050
        exit(1);
1051
      }
1052
      eval_hash_mask = eval_hash_table_size - 1;
33 pmbaty 1053
    }
108 pmbaty 1054
    Print(32, "eval hash table memory = %s bytes",
1055
        DisplayKMB(eval_hash_table_size * sizeof(uint64_t), 1));
1056
    Print(32, " (%s entries).\n", DisplayKMB(eval_hash_table_size, 1));
1057
    InitializeHashTables(old_hash_size != eval_hash_table_size);
33 pmbaty 1058
  }
1059
/*
1060
 ************************************************************
1061
 *                                                          *
1062
 *  "help" command lists commands/options.                  *
1063
 *                                                          *
1064
 ************************************************************
1065
 */
1066
  else if (OptionMatch("help", *args)) {
1067
    FILE *helpfile;
1068
    char *readstat = (char *) -1;
1069
    int lines = 0;
1070
 
108 pmbaty 1071
    helpfile = fopen("crafty.hlp", "r");
33 pmbaty 1072
    if (!helpfile) {
1073
      printf("ERROR.  Unable to open \"crafty.hlp\" -- help unavailable\n");
1074
      return 1;
1075
    }
1076
    if (nargs > 1) {
1077
      while (1) {
1078
        readstat = fgets(buffer, 128, helpfile);
1079
        if (!readstat) {
1080
          printf("Sorry, no help available for \"%s\"\n", args[1]);
1081
          fclose(helpfile);
1082
          return 1;
1083
        }
1084
        if (buffer[0] == '<') {
1085
          if (strstr(buffer, args[1]))
1086
            break;
1087
        }
1088
      }
1089
    }
1090
    while (1) {
1091
      readstat = fgets(buffer, 128, helpfile);
1092
      if (!readstat)
1093
        break;
1094
      if (strchr(buffer, '\n'))
1095
        *strchr(buffer, '\n') = 0;
1096
      if (!strcmp(buffer, "<end>"))
1097
        break;
1098
      printf("%s\n", buffer);
1099
      lines++;
1100
      if (lines > 22) {
1101
        lines = 0;
1102
        printf("<return> for more...");
1103
        fflush(stdout);
108 pmbaty 1104
        Read(1, buffer);
33 pmbaty 1105
      }
1106
    }
1107
    fclose(helpfile);
1108
  }
1109
/*
1110
 ************************************************************
1111
 *                                                          *
1112
 *  "hint" displays the expected move based on the last     *
1113
 *  search done. [xboard compatibility]                     *
1114
 *                                                          *
1115
 ************************************************************
1116
 */
108 pmbaty 1117
  else if (OptionMatch("hint", *args)) {
1118
    if (strlen(ponder_text)) {
1119
      printf("Hint: %s\n", ponder_text);
33 pmbaty 1120
      fflush(stdout);
1121
    }
1122
  }
1123
/*
1124
 ************************************************************
1125
 *                                                          *
1126
 *  "input" command directs the program to read input from  *
1127
 *  a file until eof is reached or an "exit" command is     *
1128
 *  encountered while reading the file.                     *
1129
 *                                                          *
1130
 ************************************************************
1131
 */
1132
  else if (OptionMatch("input", *args)) {
1133
    if (thinking || pondering)
1134
      return 2;
1135
    nargs = ReadParse(buffer, args, " \t=");
1136
    if (nargs < 2) {
1137
      printf("usage:  input <filename>\n");
1138
      return 1;
1139
    }
108 pmbaty 1140
    if (!(input_stream = fopen(args[1], "r"))) {
33 pmbaty 1141
      printf("file does not exist.\n");
1142
      input_stream = stdin;
1143
    }
1144
  }
1145
/*
1146
 ************************************************************
1147
 *                                                          *
1148
 *  "info" command gives some information about Crafty.     *
1149
 *                                                          *
1150
 ************************************************************
1151
 */
1152
  else if (OptionMatch("info", *args)) {
108 pmbaty 1153
    Print(32, "Crafty version %s\n", version);
1154
    Print(32, "number of threads =         %2d\n", smp_max_threads);
1155
    Print(32, "hash table memory = %s bytes", DisplayKMB(hash_table_size * 64,
1156
            1));
1157
    Print(32, " (%s entries).\n", DisplayKMB(hash_table_size * 5, 0));
1158
    Print(32, "pawn hash table memory = %5s\n",
1159
        DisplayKMB(pawn_hash_table_size * sizeof(PAWN_HASH_ENTRY), 1));
33 pmbaty 1160
#if !defined(NOEGTB)
108 pmbaty 1161
    Print(32, "EGTB cache memory =      %5s\n", DisplayKMB(EGTB_cache_size,
1162
            1));
33 pmbaty 1163
#endif
1164
    if (!tc_sudden_death) {
108 pmbaty 1165
      Print(32, "%d moves/%d minutes %d seconds primary time control\n",
33 pmbaty 1166
          tc_moves, tc_time / 6000, (tc_time / 100) % 60);
108 pmbaty 1167
      Print(32, "%d moves/%d minutes %d seconds secondary time control\n",
33 pmbaty 1168
          tc_secondary_moves, tc_secondary_time / 6000,
1169
          (tc_secondary_time / 100) % 60);
1170
      if (tc_increment)
108 pmbaty 1171
        Print(32, "increment %d seconds.\n", tc_increment / 100);
33 pmbaty 1172
    } else if (tc_sudden_death == 1) {
108 pmbaty 1173
      Print(32, " game/%d minutes primary time control\n", tc_time / 6000);
33 pmbaty 1174
      if (tc_increment)
108 pmbaty 1175
        Print(32, "increment %d seconds.\n", (tc_increment / 100) % 60);
33 pmbaty 1176
    } else if (tc_sudden_death == 2) {
108 pmbaty 1177
      Print(32, "%d moves/%d minutes primary time control\n", tc_moves,
33 pmbaty 1178
          tc_time / 6000);
108 pmbaty 1179
      Print(32, "game/%d minutes secondary time control\n",
33 pmbaty 1180
          tc_secondary_time / 6000);
1181
      if (tc_increment)
108 pmbaty 1182
        Print(32, "increment %d seconds.\n", tc_increment / 100);
33 pmbaty 1183
    }
108 pmbaty 1184
    Print(32, "book frequency (freq)..............%4.2f\n", book_weight_freq);
1185
    Print(32, "book static evaluation (eval)......%4.2f\n", book_weight_eval);
1186
    Print(32, "book learning (learn)..............%4.2f\n",
33 pmbaty 1187
        book_weight_learn);
1188
  }
1189
/*
1190
 ************************************************************
1191
 *                                                          *
1192
 *  "kibitz" command sets kibitz mode for ICS.  =1 will     *
1193
 *  kibitz mate announcements, =2 will kibitz scores and    *
1194
 *  other info, =3 will kibitz scores and PV, =4 adds the   *
1195
 *  list of book moves, =5 displays the PV after each       *
108 pmbaty 1196
 *  iteration completes.                                    *
33 pmbaty 1197
 *                                                          *
1198
 ************************************************************
1199
 */
1200
  else if (OptionMatch("kibitz", *args)) {
1201
    if (nargs < 2) {
1202
      printf("usage:  kibitz <level>\n");
1203
      return 1;
1204
    }
108 pmbaty 1205
    kibitz = Min(5, atoi(args[1]));
33 pmbaty 1206
  }
1207
/*
1208
 ************************************************************
1209
 *                                                          *
1210
 *  "learn" command enables/disables the learning           *
1211
 *  algorithm used in Crafty.  this is controlled by a      *
1212
 *  single variable that is either 0 or 1 (disabled or      *
1213
 *  enabled).                                               *
1214
 *                                                          *
1215
 *  "learn clear" clears all learning data in the opening   *
1216
 *  book, returning it to a state identical to when the     *
1217
 *  book was originally created.                            *
1218
 *                                                          *
1219
 ************************************************************
1220
 */
1221
  else if (OptionMatch("learn", *args)) {
1222
    if (nargs == 2) {
1223
      if (OptionMatch("clear", *(args + 1))) {
1224
        int index[32768], i, j, cluster;
1225
        unsigned char buf32[4];
1226
 
1227
        fseek(book_file, 0, SEEK_SET);
1228
        for (i = 0; i < 32768; i++) {
108 pmbaty 1229
          v = fread(buf32, 4, 1, book_file);
1230
          if (v <= 0)
1231
            perror("Option() fread error: ");
33 pmbaty 1232
          index[i] = BookIn32(buf32);
1233
        }
1234
        for (i = 0; i < 32768; i++)
1235
          if (index[i] > 0) {
1236
            fseek(book_file, index[i], SEEK_SET);
108 pmbaty 1237
            v = fread(buf32, 4, 1, book_file);
1238
            if (v <= 0)
1239
              perror("Option() fread error: ");
33 pmbaty 1240
            cluster = BookIn32(buf32);
108 pmbaty 1241
            if (cluster)
1242
              BookClusterIn(book_file, cluster, book_buffer);
33 pmbaty 1243
            for (j = 0; j < cluster; j++)
1244
              book_buffer[j].learn = 0.0;
1245
            fseek(book_file, index[i] + sizeof(int), SEEK_SET);
108 pmbaty 1246
            if (cluster)
1247
              BookClusterOut(book_file, cluster, book_buffer);
33 pmbaty 1248
          }
1249
      } else {
1250
        learning = atoi(args[1]);
1251
        learn = (learning > 0) ? 1 : 0;
1252
        if (learning)
108 pmbaty 1253
          Print(32, "book learning enabled {-%d,+%d}\n", learning, learning);
33 pmbaty 1254
        else
108 pmbaty 1255
          Print(32, "book learning disabled\n");
33 pmbaty 1256
      }
1257
    }
1258
  }
1259
/*
1260
 ************************************************************
1261
 *                                                          *
1262
 *  "level" command sets time controls [xboard compati-     *
1263
 *  bility.]                                                *
1264
 *                                                          *
1265
 ************************************************************
1266
 */
1267
  else if (OptionMatch("level", *args)) {
1268
    if (nargs < 4) {
1269
      printf("usage:  level <nmoves> <stime> <inc>\n");
1270
      return 1;
1271
    }
1272
    tc_moves = atoi(args[1]);
1273
    tc_time = atoi(args[2]) * 60;
1274
    if (strchr(args[2], ':'))
1275
      tc_time = tc_time + atoi(strchr(args[2], ':') + 1);
1276
    tc_time *= 100;
1277
    tc_increment = atoi(args[3]) * 100;
1278
    tc_time_remaining[white] = tc_time;
1279
    tc_time_remaining[black] = tc_time;
1280
    if (!tc_moves) {
1281
      tc_sudden_death = 1;
1282
      tc_moves = 1000;
1283
      tc_moves_remaining[white] = 1000;
1284
      tc_moves_remaining[black] = 1000;
1285
    } else
1286
      tc_sudden_death = 0;
1287
    if (tc_moves) {
1288
      tc_secondary_moves = tc_moves;
1289
      tc_secondary_time = tc_time;
1290
      tc_moves_remaining[white] = tc_moves;
1291
      tc_moves_remaining[black] = tc_moves;
1292
    }
1293
    if (!tc_sudden_death) {
108 pmbaty 1294
      Print(32, "%d moves/%d seconds primary time control\n", tc_moves,
33 pmbaty 1295
          tc_time / 100);
108 pmbaty 1296
      Print(32, "%d moves/%d seconds secondary time control\n",
33 pmbaty 1297
          tc_secondary_moves, tc_secondary_time / 100);
1298
      if (tc_increment)
108 pmbaty 1299
        Print(32, "increment %d seconds.\n", tc_increment / 100);
33 pmbaty 1300
    } else if (tc_sudden_death == 1) {
108 pmbaty 1301
      Print(32, " game/%d seconds primary time control\n", tc_time / 100);
33 pmbaty 1302
      if (tc_increment)
108 pmbaty 1303
        Print(32, "increment %d seconds.\n", tc_increment / 100);
33 pmbaty 1304
    }
1305
    if (adaptive_hash) {
108 pmbaty 1306
      uint64_t positions_per_move;
33 pmbaty 1307
      float percent;
1308
      int optimal_hash_size;
1309
 
1310
      TimeSet(think);
1311
      time_limit /= 100;
1312
      positions_per_move = time_limit * adaptive_hash / 16;
108 pmbaty 1313
      optimal_hash_size = (int) positions_per_move * 16; // Pierre-Marie Baty -- added type cast
33 pmbaty 1314
      printf("optimal=%d\n", optimal_hash_size);
1315
      optimal_hash_size = Max(optimal_hash_size, (int) adaptive_hash_min); // Pierre-Marie Baty -- added type cast
1316
      optimal_hash_size = Min(optimal_hash_size, (int) adaptive_hash_max); // Pierre-Marie Baty -- added type cast
108 pmbaty 1317
      sprintf(buffer, "hash=%d\n", optimal_hash_size);
1318
      Option(tree);
33 pmbaty 1319
      percent =
1320
          (float) (optimal_hash_size -
1321
          adaptive_hash_min) / (float) (adaptive_hash_max -
1322
          adaptive_hash_min);
108 pmbaty 1323
      optimal_hash_size = (int) // Pierre-Marie Baty -- added type cast
1324
          (adaptive_hashp_min + percent * (adaptive_hashp_max -
1325
          adaptive_hashp_min));
33 pmbaty 1326
      optimal_hash_size = Max(optimal_hash_size, (int) adaptive_hashp_min); // Pierre-Marie Baty -- added type cast
108 pmbaty 1327
      sprintf(buffer, "hashp=%d\n", optimal_hash_size);
1328
      Option(tree);
33 pmbaty 1329
    }
1330
  }
1331
/*
1332
 ************************************************************
1333
 *                                                          *
1334
 *  "linelength" sets the default line length to something  *
1335
 *  other than 80, if desired.  Setting this to a huge      *
1336
 *  number makes a PV print on one line for easier parsing  *
1337
 *  by automated scripts.                                   *
1338
 *                                                          *
1339
 ************************************************************
1340
 */
1341
  else if (OptionMatch("linelength", *args)) {
1342
    if (nargs > 2) {
1343
      printf("usage:  linelength <n>\n");
1344
      return 1;
1345
    }
1346
    if (nargs == 2)
1347
      line_length = atoi(args[1]);
1348
    printf("line length set to %d.\n", line_length);
1349
  }
1350
/*
1351
 ************************************************************
1352
 *                                                          *
1353
 *  "list" command allows the operator to add or remove     *
1354
 *  names from the various lists Crafty uses to recognize   *
1355
 *  and adapt to particular opponents.                      *
1356
 *                                                          *
1357
 *  list <listname> <player>                                *
1358
 *                                                          *
1359
 *  <listname> is one of AK, B, C, GM, IM, SP.              *
1360
 *                                                          *
1361
 *  The final parameter is a name to add  or remove.  If    *
1362
 *  you prepend a + to the name, that asks that the name be *
1363
 *  added to the list.  If you prepend a - to the name,     *
1364
 *  that asks that the name be removed from the list.  If   *
1365
 *  no name is given, the list is displayed.                *
1366
 *                                                          *
1367
 *  AK is the "auto-kibitz" list.  Crafty will kibitz info  *
1368
 *  on a chess server when playing any opponent in this     *
1369
 *  list.  This should only have computer names as humans   *
1370
 *  don't approve of kibitzes while they are playing.       *
1371
 *                                                          *
1372
 *  B identifies "blocker" players, those that try to       *
1373
 *  block the position and go for easy draws.  This makes   *
1374
 *  Crafty try much harder to prevent this from happening,  *
1375
 *  even at the expense of positional compensation.         *
1376
 *                                                          *
1377
 *  GM and IM identify titled players.  This affects how    *
1378
 *  and when Crafty resigns or offers/accepts draws.  For   *
1379
 *  GM players it will do so fairly early after the right   *
1380
 *  circumstances have been seen, for IM it delays a bit    *
1381
 *  longer as they are more prone to making a small error   *
1382
 *  that avoids the loss or draw.                           *
1383
 *                                                          *
1384
 *  SP is the "special player" option.  This is an extended *
1385
 *  version of the "list" command that allows you to        *
1386
 *  specify a special "start book" for a particular         *
1387
 *  opponent to make Crafty play specific openings against  *
1388
 *  that opponent, as well as allowing you to specify a     *
1389
 *  personality file to use against that specific opponent  *
1390
 *  when he is identified by the correct "name" command.    *
1391
 *                                                          *
1392
 *  For the SP list, the command is extended to use         *
1393
 *                                                          *
1394
 *  "list SP +player book=filename  personality=filename"   *
1395
 *                                                          *
1396
 *  For the SP list, the files specified must exist in the  *
1397
 *  current directory unless the bookpath and perspath      *
1398
 *  commands direct Crafty to look elsewhere.               *
1399
 *                                                          *
1400
 ************************************************************
1401
 */
1402
  else if (OptionMatch("list", *args)) {
1403
    char **targs;
1404
    char listname[5][3] = { "AK", "B", "GM", "IM", "SP" };
1405
    char **listaddr[] = { AK_list, B_list, GM_list,
1406
      IM_list, SP_list
1407
    };
108 pmbaty 1408
    int i, list, lastent = -1;
1409
 
33 pmbaty 1410
    targs = args;
1411
    for (list = 0; list < 5; list++) {
1412
      if (!strcmp(listname[list], args[1]))
1413
        break;
1414
    }
1415
    if (list > 4) {
1416
      printf("usage:  list AK|B|GM|IM|P|SP +name1 -name2 etc\n");
1417
      return 1;
1418
    }
1419
    nargs -= 2;
1420
    targs += 2;
1421
    if (nargs) {
1422
      while (nargs) {
1423
        if (targs[0][0] == '-') {
1424
          for (i = 0; i < 128; i++)
1425
            if (listaddr[list][i]) {
1426
              if (!strcmp(listaddr[list][i], targs[0] + 1)) {
1427
                free(listaddr[list][i]);
1428
                listaddr[list][i] = NULL;
108 pmbaty 1429
                Print(32, "%s removed from %s list.\n", targs[0] + 1,
33 pmbaty 1430
                    listname[list]);
1431
                break;
1432
              }
1433
            }
1434
        } else if (targs[0][0] == '+') {
1435
          for (i = 0; i < 128; i++)
1436
            if (listaddr[list][i]) {
1437
              if (!strcmp(listaddr[list][i], targs[0] + 1)) {
108 pmbaty 1438
                Print(32, "Warning: %s is already in %s list.\n",
33 pmbaty 1439
                    targs[0] + 1, listname[list]);
1440
                break;
1441
              }
1442
            }
1443
          for (i = 0; i < 128; i++)
1444
            if (listaddr[list][i] == NULL)
1445
              break;
1446
          if (i >= 128)
108 pmbaty 1447
            Print(32, "ERROR!  %s list is full at 128 entries\n",
33 pmbaty 1448
                listname[list]);
1449
          else {
1450
            listaddr[list][i] = malloc(strlen(targs[0]));
1451
            strcpy(listaddr[list][i], targs[0] + 1);
108 pmbaty 1452
            Print(32, "%s added to %s list.\n", targs[0] + 1, listname[list]);
33 pmbaty 1453
            if (list == 5)
1454
              lastent = i;
1455
          }
1456
        } else if (!strcmp(targs[0], "clear")) {
1457
          for (i = 0; i < 128; i++) {
1458
            free(listaddr[list][i]);
1459
            listaddr[list][i] = NULL;
1460
          }
1461
        } else if (!strcmp(targs[0], "book") && lastent != -1) {
1462
          char filename[256];
1463
          FILE *file;
1464
 
108 pmbaty 1465
          strcpy(filename, book_path);
1466
          strcat(filename, "/");
1467
          strcat(filename, targs[1]);
33 pmbaty 1468
          if (!strstr(args[2], ".bin"))
108 pmbaty 1469
            strcat(filename, ".bin");
1470
          file = fopen(filename, "r");
33 pmbaty 1471
          if (!file) {
1472
            Print(4095, "ERROR  book file %s can not be opened\n", filename);
1473
            break;
1474
          }
1475
          fclose(file);
1476
          SP_opening_filename[lastent] = malloc(strlen(filename) + 1);
1477
          strcpy(SP_opening_filename[lastent], filename);
1478
          nargs--;
1479
          targs++;
1480
        } else if (!strcmp(targs[0], "personality") && lastent != -1) {
1481
          char filename[256];
1482
          FILE *file;
1483
 
1484
          strcat(filename, targs[1]);
1485
          if (!strstr(args[2], ".cpf"))
1486
            strcat(filename, ".cpf");
1487
          file = fopen(filename, "r");
1488
          if (!file) {
1489
            Print(4095, "ERROR  personality file %s can not be opened\n",
1490
                filename);
1491
            break;
1492
          }
1493
          fclose(file);
1494
          SP_personality_filename[lastent] = malloc(strlen(filename) + 1);
1495
          strcpy(SP_personality_filename[lastent], filename);
1496
          nargs--;
1497
          targs++;
1498
        } else
1499
          printf("error, name must be preceeded by +/- flag.\n");
1500
        nargs--;
1501
        targs++;
1502
      }
1503
    } else {
108 pmbaty 1504
      Print(32, "%s List:\n", listname[list]);
33 pmbaty 1505
      for (i = 0; i < 128; i++) {
1506
        if (listaddr[list][i]) {
108 pmbaty 1507
          Print(32, "%s", listaddr[list][i]);
33 pmbaty 1508
          if (list == 5) {
1509
            if (SP_opening_filename[i])
108 pmbaty 1510
              Print(32, "  book=%s", SP_opening_filename[i]);
33 pmbaty 1511
            if (SP_personality_filename[i])
108 pmbaty 1512
              Print(32, "  personality=%s", SP_personality_filename[i]);
33 pmbaty 1513
          }
108 pmbaty 1514
          Print(32, "\n");
33 pmbaty 1515
        }
1516
      }
1517
    }
1518
  }
1519
/*
1520
 ************************************************************
1521
 *                                                          *
108 pmbaty 1522
 *  "lmr" command sets the formla parameters that produce   *
1523
 *  LMR reduction matrix.  The format is:                   *
1524
 *                                                          *
1525
 *     lmr <min> <max> <depth bias> <moves bias> <scale>    *
1526
 *                                                          *
1527
 *  <min> is the minimum LMR reduction.  This probably      *
1528
 *  should not be changed from 1, the default.              *
1529
 *                                                          *
1530
 *  <max> is the maximum LMR reduction.  If you adjust the  *
1531
 *  following values, you might need to increase this as it *
1532
 *  is an absolute clamp and no value can exceed this no    *
1533
 *  matter what the formula produces.                       *
1534
 *                                                          *
1535
 *  <depth_bias> is simply a multiplier that causes depth   *
1536
 *  to influence the reduction amount more or less (as the  *
1537
 *  value drops below the value used for <moves bias> below *
1538
 *  or as it is increased above <moves bias>.  The default  *
1539
 *  is 2.0.                                                 *
1540
 *                                                          *
1541
 *  <moves bias> is simply a multiplier that causes the     *
1542
 *  number of moves already searched to become more or less *
1543
 *  important than the remaining depth as above.  The       *
1544
 *  default is 1.0.                                         *
1545
 *                                                          *
1546
 *  <scale> is used to scale the formula back since it uses *
1547
 *  a logarithmic expression.  The basic idea is to adjust  *
1548
 *  the above two values to produce the desired "shape" of  *
1549
 *  the reduction matrix, then adjust this to change the    *
1550
 *  reduction amounts overall.  The default is 2.9.         *
1551
 *                                                          *
1552
 ************************************************************
1553
 */
1554
  else if (OptionMatch("lmr", *args)) {
1555
    int i, j;
1556
 
1557
    if ((nargs > 1 && nargs < 6) || nargs > 7) {
1558
      printf("usage:  lmr <min> <max> <depth bias> <move bias> <scale>\n");
1559
      return 1;
1560
    }
1561
    if (nargs > 1) {
1562
      LMR_min = atoi(args[1]);
1563
      LMR_max = Min(atoi(args[2]), 15);
1564
      LMR_db = atof(args[3]);
1565
      LMR_mb = atof(args[4]);
1566
      LMR_s = atof(args[5]);
1567
      InitializeReductions();
1568
    }
1569
    if (nargs > 6) {
1570
      char *axis = "|||||||||||depth left|||||||||||";
1571
 
1572
      Print(32,
1573
          "LMR values:  %d(min) %d(max) %.2f(depth) %.2f(moves) %.2f(scale).\n",
1574
          LMR_min, LMR_max, LMR_db, LMR_mb, LMR_s);
1575
      Print(32, "\n                 LMR reductions[depth][moves]\n");
1576
      Print(32, "  ----------------------moves searched-----------------\n");
1577
      Print(32, " |      ");
1578
      for (i = 0; i < 64; i += 1)
1579
        Print(32, "%3d", i);
1580
      Print(32, "\n");
1581
      for (i = 0; i < 32; i += 1) {
1582
        Print(32, " %c %3d: ", axis[i], i);
1583
        for (j = 0; j < 64; j += 1)
1584
          Print(32, " %2d", LMR[i][j]);
1585
        Print(32, "\n");
1586
      }
1587
    } else {
1588
 
1589
      char *axis = "||depth left|||";
1590
      Print(32,
1591
          "LMR values:  %d(min) %d(max) %.2f(depth) %.2f(moves) %.2f(scale).\n",
1592
          LMR_min, LMR_max, LMR_db, LMR_mb, LMR_s);
1593
      Print(32, "\n                 LMR reductions[depth][moves]\n");
1594
      Print(32, "  ----------------------moves searched------------------\n");
1595
      Print(32, " |      ");
1596
      for (i = 2; i < 64; i += 4)
1597
        Print(32, "%3d", i);
1598
      Print(32, "\n");
1599
      for (i = 3; i < 32; i += 2) {
1600
        Print(32, " %c %3d: ", axis[(i - 3) / 2], i);
1601
        for (j = 2; j < 64; j += 4)
1602
          Print(32, " %2d", LMR[i][j]);
1603
        Print(32, "\n");
1604
      }
1605
      Print(32, "    note:  table is shown compressed, each index is in\n");
1606
      Print(32, "    units of 1, all rows/columns are not shown above\n");
1607
    }
1608
  }
1609
/*
1610
 ************************************************************
1611
 *                                                          *
33 pmbaty 1612
 *   "load" command directs the program to read input from  *
1613
 *   a file until a "setboard" command is found  this       *
1614
 *   command is then executed, setting up the position for  *
1615
 *   a search.                                              *
1616
 *                                                          *
1617
 ************************************************************
1618
 */
1619
  else if (OptionMatch("load", *args)) {
1620
    char title[64];
1621
    char *readstat;
1622
    FILE *prob_file;
1623
 
1624
    if (thinking || pondering)
1625
      return 2;
1626
    nargs = ReadParse(buffer, args, " \t=");
1627
    if (nargs < 3) {
1628
      printf("usage:  input <filename> title\n");
1629
      return 1;
1630
    }
1631
    if (!(prob_file = fopen(args[1], "r"))) {
1632
      printf("file does not exist.\n");
1633
      return 1;
1634
    }
108 pmbaty 1635
    strcpy(title, args[2]);
33 pmbaty 1636
    while (!feof(prob_file)) {
1637
      readstat = fgets(buffer, 128, prob_file);
1638
      if (readstat) {
1639
        char *delim;
1640
 
1641
        delim = strchr(buffer, '\n');
1642
        if (delim)
1643
          *delim = 0;
1644
        delim = strchr(buffer, '\r');
1645
        if (delim)
1646
          *delim = ' ';
1647
      }
1648
      if (readstat == NULL)
1649
        break;
1650
      nargs = ReadParse(buffer, args, " \t;\n");
1651
      if (!strcmp(args[0], "title") && strstr(buffer, title))
1652
        break;
1653
    }
1654
    while (!feof(prob_file)) {
1655
      readstat = fgets(buffer, 128, prob_file);
1656
      if (readstat) {
1657
        char *delim;
1658
 
1659
        delim = strchr(buffer, '\n');
1660
        if (delim)
1661
          *delim = 0;
1662
        delim = strchr(buffer, '\r');
1663
        if (delim)
1664
          *delim = ' ';
1665
      }
1666
      if (readstat == NULL)
1667
        break;
1668
      nargs = ReadParse(buffer, args, " \t;\n");
1669
      if (!strcmp(args[0], "setboard")) {
108 pmbaty 1670
        Option(tree);
33 pmbaty 1671
        break;
1672
      }
1673
    }
1674
  }
1675
/*
1676
 ************************************************************
1677
 *                                                          *
1678
 *   "log" command turns log on/off, and also lets you view *
1679
 *   the end of the log or copy it to disk as needed.  To   *
1680
 *   view the end, simply type "log <n>" where n is the #   *
1681
 *   of lines you'd like to see (the last <n> lines).  You  *
1682
 *   can add a filename to the end and the output will go   *
1683
 *   to this file instead.                                  *
1684
 *                                                          *
1685
 ************************************************************
1686
 */
1687
  else if (OptionMatch("log", *args)) {
1688
    FILE *output_file;
1689
    char filename[64], buffer[128];
1690
 
1691
    if (nargs < 2) {
1692
      printf("usage:  log on|off|n [filename]\n");
1693
      return 1;
1694
    }
1695
    if (!strcmp(args[1], "on")) {
1696
      int id;
1697
 
1698
      id = InitializeGetLogID();
108 pmbaty 1699
      sprintf(log_filename, "%s/log.%03d", log_path, id);
1700
      sprintf(history_filename, "%s/game.%03d", log_path, id);
1701
      log_file = fopen(log_filename, "w");
1702
      history_file = fopen(history_filename, "w+");
33 pmbaty 1703
    } else if (!strcmp(args[1], "off")) {
1704
      if (log_file)
1705
        fclose(log_file);
1706
      log_file = 0;
108 pmbaty 1707
      sprintf(filename, "%s/log.%03d", log_path, log_id - 1);
33 pmbaty 1708
      remove(filename);
108 pmbaty 1709
      sprintf(filename, "%s/game.%03d", log_path, log_id - 1);
33 pmbaty 1710
      remove(filename);
1711
    } else if (args[1][0] >= '0' && args[1][0] <= '9') {
1712
      if (log_id == 0)
1713
        log_id = atoi(args[1]);
1714
    } else {
1715
      char *eof;
1716
      FILE *log;
108 pmbaty 1717
      int nrecs, trecs, lrecs;
33 pmbaty 1718
 
1719
      nrecs = atoi(args[1]);
1720
      output_file = stdout;
1721
      if (nargs > 2)
1722
        output_file = fopen(args[2], "w");
1723
      log = fopen(log_filename, "r");
1724
      for (trecs = 1; trecs < 99999999; trecs++) {
1725
        eof = fgets(buffer, 128, log);
1726
        if (eof) {
1727
          char *delim;
1728
 
1729
          delim = strchr(buffer, '\n');
1730
          if (delim)
1731
            *delim = 0;
1732
          delim = strchr(buffer, '\r');
1733
          if (delim)
1734
            *delim = ' ';
1735
        } else
1736
          break;
1737
      }
1738
      fseek(log, 0, SEEK_SET);
1739
      for (lrecs = 1; lrecs < trecs - nrecs; lrecs++) {
1740
        eof = fgets(buffer, 128, log);
1741
        if (eof) {
1742
          char *delim;
1743
 
1744
          delim = strchr(buffer, '\n');
1745
          if (delim)
1746
            *delim = 0;
1747
          delim = strchr(buffer, '\r');
1748
          if (delim)
1749
            *delim = ' ';
1750
        } else
1751
          break;
1752
      }
1753
      for (; lrecs < trecs; lrecs++) {
1754
        eof = fgets(buffer, 128, log);
1755
        if (eof) {
1756
          char *delim;
1757
 
1758
          delim = strchr(buffer, '\n');
1759
          if (delim)
1760
            *delim = 0;
1761
          delim = strchr(buffer, '\r');
1762
          if (delim)
1763
            *delim = ' ';
1764
        } else
1765
          break;
1766
        fprintf(output_file, "%s\n", buffer);
1767
      }
1768
      if (output_file != stdout)
1769
        fclose(output_file);
1770
    }
1771
  }
1772
/*
1773
 ************************************************************
1774
 *                                                          *
1775
 *   "memory" command is used to set the max memory to use  *
1776
 *   for hash and hashp combined.  This is an xboard        *
1777
 *   compatibility command, not normally used by players.   *
1778
 *                                                          *
1779
 ************************************************************
1780
 */
1781
  else if (OptionMatch("memory", *args)) {
1782
    uint64_t size;
1783
    size_t hmemory, pmemory;
1784
    if (nargs < 2) {
1785
      printf("usage:  memory <size>\n");
1786
      return 1;
1787
    }
108 pmbaty 1788
    if (allow_memory) {
1789
      size = (uint64_t) atoi(args[1]);
1790
      if (size == 0) {
1791
        Print(4095, "ERROR - memory size can not be zero\n");
1792
        return 1;
1793
      }
1794
      hmemory = (1ull) << MSB(size);
1795
      size &= ~hmemory;
1796
      pmemory = (1ull) << MSB(size);
1797
      sprintf(buffer, "hash %" PRIu64 "M\n", (uint64_t) hmemory);
1798
      Option(tree);
1799
      if (pmemory) {
1800
        sprintf(buffer, "hashp %" PRIu64 "M\n", (uint64_t) pmemory);
1801
        Option(tree);
1802
      }
1803
    } else
1804
      Print(4095, "WARNING - memory command ignored.\n");
33 pmbaty 1805
  }
1806
/*
1807
 ************************************************************
1808
 *                                                          *
1809
 *   "mode" command sets tournament mode or normal mode.    *
1810
 *   Tournament mode is used when Crafty is in a "real"     *
1811
 *   tournament.  It forces draw_score to 0, and makes      *
1812
 *   Crafty display the chess clock after each move.        *
1813
 *                                                          *
1814
 ************************************************************
1815
 */
1816
  else if (OptionMatch("mode", *args)) {
1817
    if (nargs > 1) {
1818
      if (!strcmp(args[1], "tournament")) {
1819
        mode = tournament_mode;
1820
        printf("use 'settc' command if a game is restarted after Crafty\n");
1821
        printf("has been terminated for any reason.\n");
1822
      } else if (!strcmp(args[1], "normal")) {
1823
        mode = normal_mode;
1824
        book_weight_learn = 1.0;
1825
        book_weight_freq = 1.0;
1826
        book_weight_eval = 0.5;
1827
      } else if (!strcmp(args[1], "match")) {
1828
        mode = normal_mode;
108 pmbaty 1829
        book_weight_learn = 1.0;
1830
        book_weight_freq = 0.2f; // Pierre-Marie Baty -- added type cast
1831
        book_weight_eval = 0.1f; // Pierre-Marie Baty -- added type cast
33 pmbaty 1832
      } else {
1833
        printf("usage:  mode normal|tournament|match\n");
1834
        mode = normal_mode;
108 pmbaty 1835
        book_weight_learn = 1.0;
1836
        book_weight_freq = 1.0;
1837
        book_weight_eval = 0.5;
33 pmbaty 1838
      }
1839
    }
1840
    if (mode == tournament_mode)
1841
      printf("tournament mode.\n");
1842
    else if (mode == normal_mode)
1843
      printf("normal mode.\n");
1844
  }
1845
/*
1846
 ************************************************************
1847
 *                                                          *
1848
 *   "name" command saves opponents name and writes it into *
1849
 *   logfile along with the date/time.  It also scans the   *
1850
 *   list of known computers and adjusts its opening book   *
1851
 *   to play less "risky" if it matches.  If the opponent   *
1852
 *   is in the GM list, it tunes the resignation controls   *
1853
 *   to resign earlier.  Ditto for other lists that are     *
1854
 *   used to recognize specific opponents and adjust things *
1855
 *   accordingly.                                           *
1856
 *                                                          *
1857
 ************************************************************
1858
 */
1859
  else if (OptionMatch("name", *args)) {
108 pmbaty 1860
    char *next;
33 pmbaty 1861
    int i;
1862
 
1863
    if (nargs < 2) {
1864
      printf("usage:  name <name>\n");
1865
      return 1;
1866
    }
1867
    if (game_wtm) {
108 pmbaty 1868
      strcpy(pgn_white, args[1]);
1869
      sprintf(pgn_black, "Crafty %s", version);
33 pmbaty 1870
    } else {
108 pmbaty 1871
      strcpy(pgn_black, args[1]);
1872
      sprintf(pgn_white, "Crafty %s", version);
33 pmbaty 1873
    }
108 pmbaty 1874
    Print(32, "Crafty %s vs %s\n", version, args[1]);
33 pmbaty 1875
    next = args[1];
1876
    while (*next) {
1877
      *next = tolower(*next);
1878
      next++;
1879
    }
1880
    if (mode != tournament_mode) {
1881
      for (i = 0; i < 128; i++)
1882
        if (AK_list[i] && !strcmp(AK_list[i], args[1])) {
1883
          kibitz = 4;
1884
          break;
1885
        }
1886
      for (i = 0; i < 128; i++)
1887
        if (GM_list[i] && !strcmp(GM_list[i], args[1])) {
108 pmbaty 1888
          Print(32, "playing a GM!\n");
33 pmbaty 1889
          book_selection_width = 3;
1890
          resign = Min(6, resign);
1891
          resign_count = 4;
1892
          draw_count = 4;
1893
          accept_draws = 1;
1894
          kibitz = 0;
1895
          break;
1896
        }
1897
      for (i = 0; i < 128; i++)
1898
        if (IM_list[i] && !strcmp(IM_list[i], args[1])) {
108 pmbaty 1899
          Print(32, "playing an IM!\n");
33 pmbaty 1900
          book_selection_width = 4;
1901
          resign = Min(9, resign);
1902
          resign_count = 5;
1903
          draw_count = 4;
1904
          accept_draws = 1;
1905
          kibitz = 0;
1906
          break;
1907
        }
1908
      for (i = 0; i < 128; i++)
1909
        if (SP_list[i] && !strcmp(SP_list[i], args[1])) {
1910
          FILE *normal_bs_file = books_file;
1911
 
108 pmbaty 1912
          Print(32, "playing a special player!\n");
33 pmbaty 1913
          if (SP_opening_filename[i]) {
1914
            books_file = fopen(SP_opening_filename[i], "rb");
1915
            if (!books_file) {
1916
              Print(4095, "Error!  unable to open %s for player %s.\n",
1917
                  SP_opening_filename[i], SP_list[i]);
1918
              books_file = normal_bs_file;
1919
            }
1920
          }
1921
          if (SP_personality_filename[i]) {
108 pmbaty 1922
            sprintf(buffer, "personality load %s\n",
33 pmbaty 1923
                SP_personality_filename[i]);
108 pmbaty 1924
            Option(tree);
33 pmbaty 1925
          }
1926
          break;
1927
        }
1928
    }
1929
    printf("tellicsnoalias kibitz Hello from Crafty v%s! (%d cpus)\n",
1930
        version, Max(1, smp_max_threads));
1931
  }
1932
/*
1933
 ************************************************************
1934
 *                                                          *
1935
 *  "new" command initializes for a new game.               *
1936
 *                                                          *
1937
 ************************************************************
1938
 */
1939
  else if (OptionMatch("new", *args)) {
1940
    new_game = 1;
1941
    if (thinking || pondering)
1942
      return 3;
1943
    if (smp_max_threads) {
1944
      int proc;
1945
 
108 pmbaty 1946
      Print(32, "parallel threads terminated.\n");
33 pmbaty 1947
      for (proc = 1; proc < CPUS; proc++)
108 pmbaty 1948
        thread[proc].terminate = 1;
33 pmbaty 1949
    }
1950
    NewGame(0);
1951
    return 3;
1952
  }
1953
/*
1954
 ************************************************************
1955
 *                                                          *
108 pmbaty 1956
 *  "noise" command sets a minimum limit on time searched   *
1957
 *  before we start to display the normal search output.    *
1958
 *  With today's hardware and deep searches, it is easy to  *
1959
 *  get "swamped" with output.  Using "noise" you can say   *
1960
 *  "hold the output until you have searched for <x> time   *
1961
 *  (where time can be x.xx seconds or just x seconds.)     *
33 pmbaty 1962
 *                                                          *
1963
 ************************************************************
1964
 */
1965
  else if (OptionMatch("noise", *args)) {
1966
    if (nargs < 2) {
1967
      printf("usage:  noise <n>\n");
1968
      return 1;
1969
    }
108 pmbaty 1970
    noise_level = (int) (atof(args[1]) * 100); // Pierre-Marie Baty -- added type cast
1971
    Print(32, "noise level set to %.2f seconds.\n",
1972
        (float) noise_level / 100.0);
33 pmbaty 1973
  }
1974
/*
1975
 ************************************************************
1976
 *                                                          *
108 pmbaty 1977
 *  "null" command sets the minimum null-move reduction and *
1978
 *  a value that is used to compute the max reduction.      *
33 pmbaty 1979
 *                                                          *
108 pmbaty 1980
 *     null <min> <divisor>                                 *
1981
 *                                                          *
1982
 *  <min> is the minimum null move reduction.  The default  *
1983
 *  is 3 which is pretty reliable.                          *
1984
 *                                                          *
1985
 *  <divisor> increases the null move by the following      *
1986
 *  simple formula:                                         *
1987
 *                                                          *
1988
 *    null_reduction = min + depth / divisor                *
1989
 *                                                          *
1990
 *  The default value is currently 10, which will increase  *
1991
 *  R (null-move reduction) by one at any position where    *
1992
 *  depth >= 10 and < 20.  Or by two when depth > 20.  Etc. *
1993
 *                                                          *
33 pmbaty 1994
 ************************************************************
1995
 */
108 pmbaty 1996
  else if (OptionMatch("null", *args)) {
1997
 
1998
    if (nargs > 3) {
1999
      printf("usage:  null <min> <divisor>\n");
33 pmbaty 2000
      return 1;
2001
    }
108 pmbaty 2002
    if (nargs > 1) {
2003
      null_depth = atoi(args[1]);
2004
      null_divisor = atoi(args[2]);
2005
    }
2006
    Print(32, "null move:  R = %d + depth / %d\n", null_depth, null_divisor);
33 pmbaty 2007
  }
2008
/*
2009
 ************************************************************
2010
 *                                                          *
108 pmbaty 2011
 *  "otim" command sets the opponent's time remaining.      *
33 pmbaty 2012
 *  This is used to determine if the opponent is in time    *
2013
 *  trouble, and is factored into the draw score if he is.  *
2014
 *                                                          *
2015
 ************************************************************
2016
 */
108 pmbaty 2017
  else if (OptionMatch("otim", *args)) {
33 pmbaty 2018
    if (nargs < 2) {
2019
      printf("usage:  otime <time(unit=.01 secs))>\n");
2020
      return 1;
2021
    }
108 pmbaty 2022
    tc_time_remaining[game_wtm] = atoi(args[1]);
33 pmbaty 2023
    if (log_file && time_limit > 99)
2024
      fprintf(log_file, "time remaining: %s (opponent).\n",
108 pmbaty 2025
          DisplayTime(tc_time_remaining[game_wtm]));
2026
    if (call_flag && xboard && tc_time_remaining[game_wtm] < 1) {
33 pmbaty 2027
      if (crafty_is_white)
108 pmbaty 2028
        Print(32, "1-0 {Black ran out of time}\n");
33 pmbaty 2029
      else
108 pmbaty 2030
        Print(32, "0-1 {White ran out of time}\n");
33 pmbaty 2031
    }
2032
  }
2033
/*
2034
 ************************************************************
2035
 *                                                          *
2036
 *  "output" command sets long or short algebraic output.   *
2037
 *  Long is Ng1f3, while short is simply Nf3.               *
2038
 *                                                          *
2039
 ************************************************************
2040
 */
2041
  else if (OptionMatch("output", *args)) {
2042
    if (nargs < 2) {
2043
      printf("usage:  output long|short\n");
2044
      return 1;
2045
    }
2046
    if (!strcmp(args[1], "long"))
2047
      output_format = 1;
2048
    else if (!strcmp(args[1], "short"))
2049
      output_format = 0;
2050
    else
2051
      printf("usage:  output long|short\n");
2052
    if (output_format == 1)
108 pmbaty 2053
      Print(32, "output moves in long algebraic format\n");
33 pmbaty 2054
    else if (output_format == 0)
108 pmbaty 2055
      Print(32, "output moves in short algebraic format\n");
33 pmbaty 2056
  }
2057
/*
2058
 ************************************************************
2059
 *                                                          *
2060
 *  "personality" command is used to adjust the eval terms  *
2061
 *  and search options to modify the way Crafty plays.      *
2062
 *                                                          *
2063
 ************************************************************
2064
 */
2065
  else if (OptionMatch("personality", *args)) {
2066
    int i, j, param, index, value;
2067
 
2068
/*
2069
 ************************************************************
2070
 *                                                          *
2071
 *  Handle the "personality list" command and dump every-   *
2072
 *  thing the user can modify.                              *
2073
 *                                                          *
2074
 ************************************************************
2075
 */
2076
    if (nargs == 2 && !strcmp(args[1], "list")) {
2077
      printf("\n");
2078
      for (i = 0; i < 256; i++) {
2079
        if (!personality_packet[i].description)
2080
          continue;
2081
        if (personality_packet[i].value) {
2082
          switch (personality_packet[i].type) {
2083
            case 1:
2084
              printf("%3d  %s %7d\n", i, personality_packet[i].description,
108 pmbaty 2085
                  *(int *) personality_packet[i].value);
33 pmbaty 2086
              break;
2087
            case 2:
2088
              printf("%3d  %s %7d (mg) %7d (eg)\n", i,
2089
                  personality_packet[i].description,
108 pmbaty 2090
                  ((int *) personality_packet[i].value)[mg],
2091
                  ((int *) personality_packet[i].value)[eg]);
33 pmbaty 2092
              break;
2093
            case 3:
108 pmbaty 2094
              printf("%3d  %s %7.2f\n", i, personality_packet[i].description,
2095
                  *(double *) personality_packet[i].value);
33 pmbaty 2096
              break;
2097
            case 4:
108 pmbaty 2098
              printf("%3d  %s    ", i, personality_packet[i].description);
2099
              for (j = 0; j < personality_packet[i].size; j++)
2100
                printf("%4d", ((int *) personality_packet[i].value)[j]);
2101
              printf("\n");
33 pmbaty 2102
              break;
2103
          }
2104
        } else {
2105
          printf("==================================================\n");
2106
          printf("=         %s  =\n", personality_packet[i].description);
2107
          printf("==================================================\n");
2108
        }
2109
      }
2110
      printf("\n");
2111
      return 1;
2112
    }
2113
/*
2114
 ************************************************************
2115
 *                                                          *
2116
 *  Handle the "personality load" command and read in the   *
2117
 *  specified *.cpf file.                                   *
2118
 *                                                          *
2119
 ************************************************************
2120
 */
2121
    if (!strcmp(args[1], "load")) {
2122
      FILE *file;
2123
      char filename[256];
2124
 
108 pmbaty 2125
      strcpy(filename, args[2]);
33 pmbaty 2126
      if (!strstr(filename, ".cpf"))
108 pmbaty 2127
        strcat(filename, ".cpf");
2128
      Print(32, "Loading personality file %s\n", filename);
2129
      if ((file = fopen(filename, "r+"))) {
33 pmbaty 2130
        while (fgets(buffer, 4096, file)) {
2131
          char *delim;
2132
 
2133
          delim = strchr(buffer, '\n');
2134
          if (delim)
2135
            *delim = 0;
2136
          delim = strstr(buffer, "->");
2137
          if (delim)
2138
            *delim = 0;
2139
          delim = strchr(buffer, '\r');
2140
          if (delim)
2141
            *delim = ' ';
108 pmbaty 2142
          Option(tree);
33 pmbaty 2143
        }
2144
        fclose(file);
2145
      }
2146
      return 1;
2147
    }
2148
/*
2149
 ************************************************************
2150
 *                                                          *
2151
 *  Handle the "personality save" command and dump every-   *
2152
 *  thing that can be modified to a file.                   *
2153
 *                                                          *
2154
 ************************************************************
2155
 */
2156
    if (nargs == 3 && !strcmp(args[1], "save")) {
2157
      char filename[256];
2158
      FILE *file;
2159
 
108 pmbaty 2160
      strcpy(filename, args[2]);
33 pmbaty 2161
      if (!strstr(filename, ".cpf"))
108 pmbaty 2162
        strcat(filename, ".cpf");
2163
      file = fopen(filename, "w");
33 pmbaty 2164
      if (!file) {
2165
        printf("ERROR.  Unable to open %s for writing\n", args[2]);
2166
        return 1;
2167
      }
2168
      printf("saving to file \"%s\"\n", filename);
2169
      fprintf(file, "# Crafty v%s personality file\n", version);
2170
      for (i = 0; i < 256; i++) {
2171
        if (!personality_packet[i].description)
2172
          continue;
2173
        if (personality_packet[i].value) {
2174
          if (personality_packet[i].size <= 1)
2175
            fprintf(file, "personality %3d %7d\n", i,
108 pmbaty 2176
                *((int *) personality_packet[i].value));
33 pmbaty 2177
          else if (personality_packet[i].size > 1) {
2178
            fprintf(file, "personality %3d ", i);
2179
            for (j = 0; j < personality_packet[i].size; j++)
108 pmbaty 2180
              fprintf(file, "%d ", ((int *) personality_packet[i].value)[j]);
33 pmbaty 2181
            fprintf(file, "\n");
2182
          }
2183
        }
2184
      }
2185
      fprintf(file, "exit\n");
2186
      fclose(file);
2187
      return 1;
2188
    }
2189
/*
2190
 ************************************************************
2191
 *                                                          *
2192
 *  Handle the "personality index val" command that changes *
2193
 *  only those personality terms that are scalars.          *
2194
 *                                                          *
2195
 ************************************************************
2196
 */
2197
    param = atoi(args[1]);
2198
    value = atoi(args[2]);
2199
    if (!personality_packet[param].value) {
2200
      Print(4095, "ERROR.  evaluation term %d is not defined\n", param);
2201
      return 1;
2202
    }
2203
    if (personality_packet[param].size == 0) {
2204
      if (nargs > 3) {
2205
        printf("this eval term requires exactly 1 value.\n");
2206
        return 1;
2207
      }
108 pmbaty 2208
      *(int *) personality_packet[param].value = value;
33 pmbaty 2209
    }
2210
/*
2211
 ************************************************************
2212
 *                                                          *
2213
 *  Handle the "personality index v1 v2 .. vn" command that *
2214
 *  changes eval terms that are vectors.                    *
2215
 *                                                          *
2216
 ************************************************************
2217
 */
2218
    else {
2219
      index = nargs - 2;
2220
      if (index != personality_packet[param].size) {
2221
        printf
2222
            ("this eval term (%s [%d]) requires exactly %d values, found %d.\n",
2223
            personality_packet[param].description, param,
2224
            Abs(personality_packet[param].size), index);
2225
        return 1;
2226
      }
2227
      for (i = 0; i < index; i++)
108 pmbaty 2228
        ((int *) personality_packet[param].value)[i] = atoi(args[i + 2]);
33 pmbaty 2229
    }
2230
    InitializeKingSafety();
2231
  }
2232
/*
2233
 ************************************************************
2234
 *                                                          *
2235
 *  "bookpath", "logpath" and "tbpath" set the default      *
2236
 *  paths to locate or save these files.                    *
2237
 *                                                          *
2238
 ************************************************************
2239
 */
2240
  else if (OptionMatch("logpath", *args) || OptionMatch("bookpath", *args)
2241
      || OptionMatch("tbpath", *args)) {
2242
    if (OptionMatch("logpath", *args) || OptionMatch("bookpath", *args)) {
2243
      if (log_file)
2244
        Print(4095, "ERROR -- this must be used on command line only\n");
2245
    }
2246
    nargs = ReadParse(buffer, args, " \t=");
2247
    if (nargs < 2) {
2248
      printf("usage:  bookpath|perspath|logpath|tbpath <path>\n");
2249
      return 1;
2250
    }
2251
    if (!strchr(args[1], '(')) {
2252
      if (strstr(args[0], "bookpath"))
108 pmbaty 2253
        strcpy(book_path, args[1]);
33 pmbaty 2254
      else if (strstr(args[0], "logpath"))
108 pmbaty 2255
        strcpy(log_path, args[1]);
33 pmbaty 2256
#if !defined(NOEGTB)
2257
      else if (strstr(args[0], "tbpath"))
108 pmbaty 2258
        strcpy(tb_path, args[1]);
33 pmbaty 2259
#endif
2260
    } else {
2261
      if (strchr(args[1], ')')) {
2262
        *strchr(args[1], ')') = 0;
2263
        if (strstr(args[0], "bookpath"))
108 pmbaty 2264
          strcpy(book_path, args[1] + 1);
33 pmbaty 2265
        else if (strstr(args[0], "logpath"))
108 pmbaty 2266
          strcpy(log_path, args[1] + 1);
33 pmbaty 2267
#if !defined(NOEGTB)
2268
        else if (strstr(args[0], "tbpath"))
108 pmbaty 2269
          strcpy(tb_path, args[1] + 1);
33 pmbaty 2270
#endif
2271
      } else
2272
        Print(4095, "ERROR multiple paths must be enclosed in ( and )\n");
2273
    }
2274
  }
2275
/*
2276
 ************************************************************
2277
 *                                                          *
2278
 *  "perf" command turns times move generator/make_move.    *
2279
 *                                                          *
2280
 ************************************************************
2281
 */
2282
#define PERF_CYCLES 4000000
2283
  else if (OptionMatch("perf", *args)) {
108 pmbaty 2284
    int i, clock_before, clock_after;
2285
    unsigned *mv;
33 pmbaty 2286
    float time_used;
2287
 
2288
    if (thinking || pondering)
2289
      return 2;
2290
    clock_before = clock();
2291
    while (clock() == clock_before);
2292
    clock_before = clock();
2293
    for (i = 0; i < PERF_CYCLES; i++) {
2294
      tree->last[1] = GenerateCaptures(tree, 0, game_wtm, tree->last[0]);
2295
      tree->last[1] = GenerateNoncaptures(tree, 0, game_wtm, tree->last[1]);
2296
    }
2297
    clock_after = clock();
2298
    time_used =
2299
        ((float) clock_after - (float) clock_before) / (float) CLOCKS_PER_SEC;
2300
    printf("generated %d moves, time=%.2f seconds\n",
2301
        (int) (tree->last[1] - tree->last[0]) * PERF_CYCLES, time_used);
2302
    printf("generated %d moves per second\n",
2303
        (int) (((float) (PERF_CYCLES * (tree->last[1] -
2304
                        tree->last[0]))) / time_used));
2305
    clock_before = clock();
2306
    while (clock() == clock_before);
2307
    clock_before = clock();
2308
    for (i = 0; i < PERF_CYCLES; i++) {
2309
      tree->last[1] = GenerateCaptures(tree, 0, game_wtm, tree->last[0]);
2310
      tree->last[1] = GenerateNoncaptures(tree, 0, game_wtm, tree->last[1]);
2311
      for (mv = tree->last[0]; mv < tree->last[1]; mv++) {
108 pmbaty 2312
        MakeMove(tree, 0, game_wtm, *mv);
2313
        UnmakeMove(tree, 0, game_wtm, *mv);
33 pmbaty 2314
      }
2315
    }
2316
    clock_after = clock();
2317
    time_used =
2318
        ((float) clock_after - (float) clock_before) / (float) CLOCKS_PER_SEC;
2319
    printf("generated/made/unmade %d moves, time=%.2f seconds\n",
2320
        (int) (tree->last[1] - tree->last[0]) * PERF_CYCLES, time_used);
2321
    printf("generated/made/unmade %d moves per second\n",
2322
        (int) (((float) (PERF_CYCLES * (tree->last[1] -
2323
                        tree->last[0]))) / time_used));
2324
  }
2325
/*
2326
 ************************************************************
2327
 *                                                          *
2328
 *  "perft" command turns tests move generator/make_move.   *
2329
 *                                                          *
2330
 ************************************************************
2331
 */
2332
  else if (OptionMatch("perft", *args)) {
108 pmbaty 2333
    float time_used;
33 pmbaty 2334
    int i, clock_before, clock_after;
2335
 
2336
    if (thinking || pondering)
2337
      return 2;
2338
    clock_before = clock();
2339
    while (clock() == clock_before);
2340
    clock_before = clock();
2341
    if (nargs < 2) {
108 pmbaty 2342
      printf("usage:  perft <depth>\n");
33 pmbaty 2343
      return 1;
2344
    }
2345
    tree->status[1] = tree->status[0];
2346
    tree->last[0] = tree->move_list;
2347
    i = atoi(args[1]);
2348
    if (i <= 0) {
108 pmbaty 2349
      Print(32, "usage:  perft <maxply>\n");
33 pmbaty 2350
      return 1;
2351
    }
2352
    total_moves = 0;
2353
    OptionPerft(tree, 1, i, game_wtm);
2354
    clock_after = clock();
2355
    time_used =
2356
        ((float) clock_after - (float) clock_before) / (float) CLOCKS_PER_SEC;
2357
    printf("total moves=%" PRIu64 "  time=%.2f\n", total_moves, time_used);
2358
  }
2359
/*
2360
 ************************************************************
2361
 *                                                          *
2362
 *  "pgn" command sets the various PGN header files.        *
2363
 *                                                          *
2364
 ************************************************************
2365
 */
2366
  else if (OptionMatch("pgn", *args)) {
2367
    int i;
2368
 
2369
    if (nargs < 3) {
2370
      printf("usage:  pgn <tag> <value>\n");
2371
      return 1;
2372
    }
2373
    if (!strcmp(args[1], "Event")) {
2374
      pgn_event[0] = 0;
2375
      for (i = 2; i < nargs; i++) {
108 pmbaty 2376
        strcpy(pgn_event + strlen(pgn_event), args[i]);
2377
        strcpy(pgn_event + strlen(pgn_event), " ");
33 pmbaty 2378
      }
2379
    } else if (!strcmp(args[1], "Site")) {
2380
      pgn_site[0] = 0;
2381
      for (i = 2; i < nargs; i++) {
108 pmbaty 2382
        strcpy(pgn_site + strlen(pgn_site), args[i]);
2383
        strcpy(pgn_site + strlen(pgn_site), " ");
33 pmbaty 2384
      }
2385
    } else if (!strcmp(args[1], "Round")) {
2386
      pgn_round[0] = 0;
108 pmbaty 2387
      strcpy(pgn_round, args[2]);
33 pmbaty 2388
    } else if (!strcmp(args[1], "White")) {
2389
      pgn_white[0] = 0;
2390
      for (i = 2; i < nargs; i++) {
108 pmbaty 2391
        strcpy(pgn_white + strlen(pgn_white), args[i]);
2392
        strcpy(pgn_white + strlen(pgn_white), " ");
33 pmbaty 2393
      }
2394
    } else if (!strcmp(args[1], "WhiteElo")) {
2395
      pgn_white_elo[0] = 0;
108 pmbaty 2396
      strcpy(pgn_white_elo, args[2]);
33 pmbaty 2397
    } else if (!strcmp(args[1], "Black")) {
2398
      pgn_black[0] = 0;
2399
      for (i = 2; i < nargs; i++) {
108 pmbaty 2400
        strcpy(pgn_black + strlen(pgn_black), args[i]);
2401
        strcpy(pgn_black + strlen(pgn_black), " ");
33 pmbaty 2402
      }
2403
    } else if (!strcmp(args[1], "BlackElo")) {
2404
      pgn_black_elo[0] = 0;
108 pmbaty 2405
      strcpy(pgn_black_elo, args[2]);
33 pmbaty 2406
    }
2407
  }
2408
/*
2409
 ************************************************************
2410
 *                                                          *
2411
 *  "ping" command simply echos the argument back to xboard *
2412
 *  to let it know all previous commands have been executed *
2413
 *  and we are ready for whatever is next.                  *
2414
 *                                                          *
2415
 ************************************************************
2416
 */
108 pmbaty 2417
  else if (OptionMatch("ping", *args)) {
2418
    if (pondering)
2419
      Print(-1, "pong %s\n", args[1]);
2420
    else
33 pmbaty 2421
      pong = atoi(args[1]);
2422
  }
2423
/*
2424
 ************************************************************
2425
 *                                                          *
2426
 *  "playother" command says "position is set up, we are    *
2427
 *  waiting on the opponent to move, ponder if you want to  *
2428
 *  do so.                                                  *
2429
 *                                                          *
2430
 ************************************************************
2431
 */
108 pmbaty 2432
  else if (OptionMatch("playother", *args)) {
33 pmbaty 2433
    force = 0;
2434
  }
2435
/*
2436
 ************************************************************
2437
 *                                                          *
2438
 *  "ponder" command toggles pondering off/on or sets a     *
2439
 *  move to ponder.                                         *
2440
 *                                                          *
2441
 ************************************************************
2442
 */
2443
  else if (OptionMatch("ponder", *args)) {
2444
    if (thinking || pondering)
2445
      return 2;
2446
    if (nargs < 2) {
2447
      printf("usage:  ponder off|on|<move>\n");
2448
      return 1;
2449
    }
2450
    if (!strcmp(args[1], "on")) {
2451
      ponder = 1;
108 pmbaty 2452
      Print(32, "pondering enabled.\n");
33 pmbaty 2453
    } else if (!strcmp(args[1], "off")) {
2454
      ponder = 0;
108 pmbaty 2455
      Print(32, "pondering disabled.\n");
33 pmbaty 2456
    } else {
108 pmbaty 2457
      ponder_move = InputMove(tree, 0, game_wtm, 0, 0, args[1]);
33 pmbaty 2458
      last_pv.pathd = 0;
2459
      last_pv.pathl = 0;
2460
    }
2461
  }
2462
/*
2463
 ************************************************************
2464
 *                                                          *
2465
 *  "post/nopost" command sets/resets "show thinking" mode  *
2466
 *  for xboard compatibility.                               *
2467
 *                                                          *
2468
 ************************************************************
2469
 */
108 pmbaty 2470
  else if (OptionMatch("post", *args)) {
33 pmbaty 2471
    post = 1;
108 pmbaty 2472
  } else if (OptionMatch("nopost", *args)) {
33 pmbaty 2473
    post = 0;
2474
  }
2475
/*
2476
 ************************************************************
2477
 *                                                          *
2478
 *  "protover" command is sent by xboard to identify the    *
2479
 *  xboard protocol version and discover what the engine    *
2480
 *  can handle.                                             *
2481
 *                                                          *
2482
 ************************************************************
2483
 */
108 pmbaty 2484
  else if (OptionMatch("protover", *args)) {
33 pmbaty 2485
    int pversion = atoi(args[1]);
2486
 
2487
    if (pversion >= 1 && pversion <= 3) {
2488
      if (pversion >= 2) {
108 pmbaty 2489
        Print(-1, "feature ping=1 setboard=1 san=1 time=1 draw=1\n");
2490
        Print(-1, "feature sigint=0 sigterm=0 reuse=1 analyze=1\n");
2491
        Print(-1, "feature myname=\"Crafty-%s\" name=1\n", version);
2492
        Print(-1, "feature playother=1 colors=0 memory=%d\n", allow_memory);
33 pmbaty 2493
#if (CPUS > 1)
108 pmbaty 2494
        Print(-1, "feature smp=%d\n", allow_cores);
33 pmbaty 2495
#endif
108 pmbaty 2496
        Print(-1, "feature variants=\"normal,nocastle\"\n");
2497
        Print(-1, "feature done=1\n");
2498
        xboard_done = 1;
33 pmbaty 2499
      }
2500
    } else
2501
      Print(4095, "ERROR, bogus xboard protocol version received.\n");
2502
  }
2503
/*
2504
 ************************************************************
2505
 *                                                          *
2506
 *  "random" command is ignored. [xboard compatibility]     *
2507
 *                                                          *
2508
 ************************************************************
2509
 */
2510
  else if (OptionMatch("random", *args)) {
2511
    return xboard;
2512
  }
2513
/*
2514
 ************************************************************
2515
 *                                                          *
2516
 *  "rating" is used by xboard to set Crafty's rating and   *
2517
 *  the opponent's rating, which is used by the learning    *
2518
 *  functions.                                              *
2519
 *                                                          *
2520
 ************************************************************
2521
 */
2522
  else if (OptionMatch("rating", *args)) {
2523
    int rd;
108 pmbaty 2524
 
33 pmbaty 2525
    if (nargs < 3) {
2526
      printf("usage:  rating <Crafty> <opponent>\n");
2527
      return 1;
2528
    }
2529
    crafty_rating = atoi(args[1]);
2530
    opponent_rating = atoi(args[2]);
2531
    if (crafty_rating == 0 && opponent_rating == 0) {
2532
      crafty_rating = 2500;
2533
      opponent_rating = 2300;
2534
    }
108 pmbaty 2535
    if (dynamic_draw_score) {
2536
      rd = opponent_rating - crafty_rating;
2537
      rd = Max(Min(rd, 300), -300);
2538
      abs_draw_score = rd / 8;
2539
      if (log_file) {
2540
        fprintf(log_file, "Crafty's rating: %d.\n", crafty_rating);
2541
        fprintf(log_file, "opponent's rating: %d.\n", opponent_rating);
2542
        fprintf(log_file, "draw score: %d.\n", abs_draw_score);
2543
      }
33 pmbaty 2544
    }
2545
  }
2546
/*
2547
 ************************************************************
2548
 *                                                          *
2549
 *  "remove" command backs up the game one whole move,      *
2550
 *  leaving the opponent still on move.  It's intended for  *
2551
 *  xboard compatibility, but works in any mode.            *
2552
 *                                                          *
2553
 ************************************************************
2554
 */
108 pmbaty 2555
  else if (OptionMatch("remove", *args)) {
33 pmbaty 2556
    if (thinking || pondering)
2557
      return 2;
2558
    move_number--;
108 pmbaty 2559
    sprintf(buffer, "reset %d", move_number);
2560
    Option(tree);
33 pmbaty 2561
  }
2562
/*
2563
 ************************************************************
2564
 *                                                          *
2565
 *  "read" reads game moves in and makes them.  This can    *
2566
 *  be used in two ways:  (1) type "read" and then start    *
2567
 *  entering moves;  type "exit" when done;  (2) type       *
2568
 *  "read <filename>" to read moves in from <filename>.     *
2569
 *  Note that read will attempt to skip over "non-move"     *
2570
 *  text and try to extract moves if it can.                *
2571
 *                                                          *
2572
 *  Note that "reada" appends to the existing position,     *
2573
 *  while "read" resets the board to the start position     *
2574
 *  before reading moves.                                   *
2575
 *                                                          *
2576
 ************************************************************
2577
 */
2578
  else if (OptionMatch("read", *args) || OptionMatch("reada", *args)) {
108 pmbaty 2579
    FILE *read_input = 0;
33 pmbaty 2580
    int append, move, readstat;
2581
 
2582
    if (thinking || pondering)
2583
      return 2;
2584
    nargs = ReadParse(buffer, args, " \t=");
2585
    if (!strcmp("reada", *args))
2586
      append = 1;
2587
    else
2588
      append = 0;
2589
    ponder_move = 0;
2590
    last_pv.pathd = 0;
2591
    last_pv.pathl = 0;
2592
    if (nargs > 1) {
108 pmbaty 2593
      if (!(read_input = fopen(args[1], "r"))) {
33 pmbaty 2594
        printf("file %s does not exist.\n", args[1]);
2595
        return 1;
2596
      }
2597
    } else {
2598
      printf("type \"exit\" to terminate.\n");
2599
      read_input = stdin;
2600
    }
2601
    if (!append) {
2602
      InitializeChessBoard(tree);
2603
      game_wtm = 1;
2604
      move_number = 1;
2605
      tc_moves_remaining[white] = tc_moves;
2606
      tc_moves_remaining[black] = tc_moves;
2607
    }
2608
/*
2609
 step 1:  read in the PGN tags.
2610
 */
2611
    readstat = ReadPGN(0, 0);
2612
    do {
2613
      if (read_input == stdin) {
2614
        if (game_wtm)
2615
          printf("read.White(%d): ", move_number);
2616
        else
2617
          printf("read.Black(%d): ", move_number);
2618
        fflush(stdout);
2619
      }
2620
      readstat = ReadPGN(read_input, 0);
2621
    } while (readstat == 1);
2622
    if (readstat < 0)
2623
      return 1;
2624
/*
2625
 step 2:  read in the moves.
2626
 */
2627
    do {
2628
      move = 0;
2629
      move = ReadNextMove(tree, buffer, 0, game_wtm);
2630
      if (move) {
2631
        if (read_input != stdin) {
108 pmbaty 2632
          printf("%s ", OutputMove(tree, 0, game_wtm, move));
33 pmbaty 2633
          if (!(move_number % 8) && Flip(game_wtm))
2634
            printf("\n");
2635
        }
2636
        fseek(history_file, ((move_number - 1) * 2 + 1 - game_wtm) * 10,
2637
            SEEK_SET);
108 pmbaty 2638
        fprintf(history_file, "%9s\n", OutputMove(tree, 0, game_wtm, move));
2639
        MakeMoveRoot(tree, game_wtm, move);
2640
        TimeAdjust(game_wtm, 0);
33 pmbaty 2641
#if defined(DEBUG)
2642
        ValidatePosition(tree, 1, move, "Option()");
2643
#endif
2644
      } else if (!read_input)
2645
        printf("illegal move.\n");
2646
      if (move) {
2647
        game_wtm = Flip(game_wtm);
2648
        if (game_wtm)
2649
          move_number++;
2650
      }
2651
      if (read_input == stdin) {
2652
        if (game_wtm)
2653
          printf("read.White(%d): ", move_number);
2654
        else
2655
          printf("read.Black(%d): ", move_number);
2656
        fflush(stdout);
2657
      }
2658
      readstat = ReadPGN(read_input, 0);
2659
      if (readstat < 0)
2660
        break;
2661
      if (!strcmp(buffer, "exit"))
2662
        break;
2663
    } while (1);
2664
    moves_out_of_book = 0;
2665
    printf("NOTICE: %d moves to next time control\n",
2666
        tc_moves_remaining[root_wtm]);
2667
    root_wtm = !game_wtm;
2668
    if (read_input != stdin) {
2669
      printf("\n");
2670
      fclose(read_input);
2671
    }
2672
  }
2673
/*
2674
 ************************************************************
2675
 *                                                          *
2676
 *  "rejected" handles the new xboard protocol version 2    *
2677
 *  rejected command.                                       *
2678
 *                                                          *
2679
 ************************************************************
2680
 */
2681
  else if (OptionMatch("rejected", *args)) {
2682
    Print(4095, "ERROR.  feature %s rejected by xboard\n", args[1]);
2683
  }
2684
/*
2685
 ************************************************************
2686
 *                                                          *
108 pmbaty 2687
 *  "reset" restores (backs up) a game to a prior position  *
2688
 *  with the same side on move.  Reset 17 would reset the   *
2689
 *  position to what it was at move 17 with the current     *
2690
 *  still on move (you can use white/black commands to      *
2691
 *  change the side to move first, if needed.)              *
2692
 *                                                          *
2693
 ************************************************************
2694
 */
2695
  else if (OptionMatch("reset", *args)) {
2696
    int i, move, nmoves;
2697
 
2698
    if (!history_file)
2699
      return 1;
2700
    if (thinking || pondering)
2701
      return 2;
2702
    if (nargs < 2) {
2703
      printf("usage:  reset <movenumber>\n");
2704
      return 1;
2705
    }
2706
    ponder_move = 0;
2707
    last_mate_score = 0;
2708
    last_pv.pathd = 0;
2709
    last_pv.pathl = 0;
2710
    if (thinking || pondering)
2711
      return 2;
2712
    over = 0;
2713
    move_number = atoi(args[1]);
2714
    if (!move_number) {
2715
      move_number = 1;
2716
      return 1;
2717
    }
2718
    nmoves = (move_number - 1) * 2 + 1 - game_wtm;
2719
    root_wtm = Flip(game_wtm);
2720
    InitializeChessBoard(tree);
2721
    game_wtm = 1;
2722
    move_number = 1;
2723
    tc_moves_remaining[white] = tc_moves;
2724
    tc_moves_remaining[black] = tc_moves;
2725
    for (i = 0; i < nmoves; i++) {
2726
      fseek(history_file, i * 10, SEEK_SET);
2727
      v = fscanf(history_file, "%s", buffer);
2728
      if (v <= 0)
2729
        perror("Option() fscanf error: ");
2730
/*
2731
 If the move is "pass", that means that the side on move passed.
2732
 This includes the case where the game started from a black-to-move
2733
 position; then white's first move is recorded as a pass.
2734
 */
2735
      if (strcmp(buffer, "pass") == 0) {
2736
        game_wtm = Flip(game_wtm);
2737
        if (game_wtm)
2738
          move_number++;
2739
        continue;
2740
      }
2741
      move = InputMove(tree, 0, game_wtm, 0, 0, buffer);
2742
      if (move)
2743
        MakeMoveRoot(tree, game_wtm, move);
2744
      else {
2745
        printf("ERROR!  move %s is illegal\n", buffer);
2746
        break;
2747
      }
2748
      TimeAdjust(game_wtm, 0);
2749
      game_wtm = Flip(game_wtm);
2750
      if (game_wtm)
2751
        move_number++;
2752
    }
2753
    moves_out_of_book = 0;
2754
    printf("NOTICE: %d moves to next time control\n",
2755
        tc_moves_remaining[root_wtm]);
2756
  }
2757
/*
2758
 ************************************************************
2759
 *                                                          *
33 pmbaty 2760
 *  "resign" command sets the resignation threshold to the  *
2761
 *  number of pawns the program must be behind before       *
2762
 *  resigning (0 -> disable resignations).  Resign with no  *
2763
 *  arguments will mark the pgn result as lost by the       *
2764
 *  opponent.                                               *
2765
 *                                                          *
2766
 ************************************************************
2767
 */
2768
  else if (OptionMatch("resign", *args)) {
2769
    if (nargs < 2) {
2770
      if (crafty_is_white) {
2771
        Print(4095, "result 1-0\n");
108 pmbaty 2772
        strcpy(pgn_result, "1-0");
33 pmbaty 2773
      } else {
2774
        Print(4095, "result 0-1\n");
108 pmbaty 2775
        strcpy(pgn_result, "0-1");
33 pmbaty 2776
      }
2777
      learn_value = 300;
2778
      LearnBook();
2779
      return 1;
2780
    }
2781
    resign = atoi(args[1]);
2782
    if (nargs == 3)
2783
      resign_count = atoi(args[2]);
2784
    if (resign)
108 pmbaty 2785
      Print(32, "resign after %d consecutive moves with score < %d.\n",
33 pmbaty 2786
          resign_count, -resign);
2787
    else
108 pmbaty 2788
      Print(32, "disabled resignations.\n");
33 pmbaty 2789
  }
2790
/*
2791
 ************************************************************
2792
 *                                                          *
2793
 *  "result" command comes from xboard/winboard and gives   *
2794
 *  the result of the current game.  If learning routines   *
2795
 *  have not yet been activated, this will do it.           *
2796
 *                                                          *
2797
 ************************************************************
2798
 */
2799
  else if (OptionMatch("result", *args)) {
2800
    if (nargs > 1) {
2801
      if (!strcmp(args[1], "1-0")) {
108 pmbaty 2802
        strcpy(pgn_result, "1-0");
33 pmbaty 2803
        if (crafty_is_white)
2804
          learn_value = 300;
2805
        else
2806
          learn_value = -300;
2807
      } else if (!strcmp(args[1], "0-1")) {
108 pmbaty 2808
        strcpy(pgn_result, "0-1");
33 pmbaty 2809
        if (crafty_is_white)
2810
          learn_value = -300;
2811
        else
2812
          learn_value = 300;
2813
      } else if (!strcmp(args[1], "1/2-1/2")) {
108 pmbaty 2814
        strcpy(pgn_result, "1/2-1/2");
33 pmbaty 2815
        learn_value = 1;
2816
      }
2817
      LearnBook();
2818
      return 1;
2819
    }
2820
  }
2821
/*
2822
 ************************************************************
2823
 *                                                          *
108 pmbaty 2824
 *  "safety" command sets a specific time safety margin     *
2825
 *  target for normal timed games.  This can generally be   *
2826
 *  left at the default value unless Crafty is being        *
2827
 *  manually operated.                                      *
2828
 *                                                          *
2829
 ************************************************************
2830
 */
2831
  else if (OptionMatch("safety", *args)) {
2832
    if (nargs == 2)
2833
      tc_safety_margin = atoi(args[1]) * 100;
2834
    Print(32, "safety margin set to %s.\n", DisplayTime(tc_safety_margin));
2835
  }
2836
/*
2837
 ************************************************************
2838
 *                                                          *
33 pmbaty 2839
 *  "savegame" command saves the game in a file in PGN      *
2840
 *  format.  Command has an optional filename.              *
2841
 *                                                          *
2842
 ************************************************************
2843
 */
2844
  else if (OptionMatch("savegame", *args)) {
2845
    struct tm *timestruct;
108 pmbaty 2846
    FILE *output_file;
2847
    time_t secs;
33 pmbaty 2848
    int i, more, swtm;
2849
    char input[128], text[128], *next;
2850
 
2851
    output_file = stdout;
2852
    secs = time(0);
2853
    timestruct = localtime((time_t *) & secs);
2854
    if (nargs > 1) {
108 pmbaty 2855
      if (!(output_file = fopen(args[1], "w"))) {
33 pmbaty 2856
        printf("unable to open %s for write.\n", args[1]);
2857
        return 1;
2858
      }
2859
    }
2860
    fprintf(output_file, "[Event \"%s\"]\n", pgn_event);
2861
    fprintf(output_file, "[Site \"%s\"]\n", pgn_site);
2862
    fprintf(output_file, "[Date \"%4d.%02d.%02d\"]\n",
2863
        timestruct->tm_year + 1900, timestruct->tm_mon + 1,
2864
        timestruct->tm_mday);
2865
    fprintf(output_file, "[Round \"%s\"]\n", pgn_round);
2866
    fprintf(output_file, "[White \"%s\"]\n", pgn_white);
2867
    fprintf(output_file, "[WhiteElo \"%s\"]\n", pgn_white_elo);
2868
    fprintf(output_file, "[Black \"%s\"]\n", pgn_black);
2869
    fprintf(output_file, "[BlackElo \"%s\"]\n", pgn_black_elo);
2870
    fprintf(output_file, "[Result \"%s\"]\n", pgn_result);
2871
/* Handle setup positions and initial pass by white */
2872
    swtm = 1;
2873
    if (move_number > 1 || !game_wtm) {
2874
      fseek(history_file, 0, SEEK_SET);
108 pmbaty 2875
      if (fscanf(history_file, "%s", input) == 1 &&
33 pmbaty 2876
          strcmp(input, "pass") == 0)
2877
        swtm = 0;
2878
    }
2879
    if (initial_position[0])
2880
      fprintf(output_file, "[FEN \"%s\"]\n[SetUp \"1\"]\n", initial_position);
2881
    else if (!swtm) {
2882
      fprintf(output_file,
2883
          "[FEN \"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR b KQkq - 0 1\"\n"
2884
          "[SetUp \"1\"]\n");
2885
    }
2886
    fprintf(output_file, "\n");
2887
    next = text;
2888
    if (!swtm) {
108 pmbaty 2889
      strcpy(next, "1... ");
33 pmbaty 2890
      next = text + strlen(text);
2891
    }
2892
/* Output the moves */
2893
    more = 0;
2894
    for (i = (swtm ? 0 : 1); i < (move_number - 1) * 2 - game_wtm + 1; i++) {
2895
      fseek(history_file, i * 10, SEEK_SET);
108 pmbaty 2896
      v = fscanf(history_file, "%s", input);
2897
      if (v <= 0)
2898
        perror("Option() fscanf error: ");
33 pmbaty 2899
      if (!(i % 2)) {
2900
        sprintf(next, "%d. ", i / 2 + 1);
2901
        next = text + strlen(text);
2902
      }
2903
      sprintf(next, "%s ", input);
2904
      next = text + strlen(text);
2905
      more = 1;
2906
      if (next - text >= 60) {
2907
        fprintf(output_file, "%s\n", text);
2908
        more = 0;
2909
        next = text;
2910
      }
2911
    }
2912
    if (more)
2913
      fprintf(output_file, "%s", text);
2914
    fprintf(output_file, "%s\n", pgn_result);
2915
    if (output_file != stdout)
2916
      fclose(output_file);
2917
    printf("PGN save complete.\n");
2918
  }
2919
/*
2920
 ************************************************************
2921
 *                                                          *
2922
 *  "savepos" command saves the current position in a FEN   *
2923
 *  (Forsythe-Edwards Notation) string that can be later    *
2924
 *  used to recreate this exact position.                   *
2925
 *                                                          *
2926
 ************************************************************
2927
 */
2928
  else if (OptionMatch("savepos", *args)) {
108 pmbaty 2929
    FILE *output_file;
33 pmbaty 2930
    int rank, file, nempty;
2931
 
2932
    output_file = stdout;
2933
    if (nargs > 1) {
2934
      if (!strcmp(args[1], "*")) {
2935
        output_file = 0;
108 pmbaty 2936
        strcpy(initial_position, "");
33 pmbaty 2937
      } else if (!(output_file = fopen(args[1], "w"))) {
2938
        printf("unable to open %s for write.\n", args[1]);
2939
        return 1;
2940
      }
2941
    }
2942
    if (output_file)
2943
      fprintf(output_file, "setboard ");
2944
    for (rank = RANK8; rank >= RANK1; rank--) {
2945
      nempty = 0;
2946
      for (file = FILEA; file <= FILEH; file++) {
2947
        if (PcOnSq((rank << 3) + file)) {
2948
          if (nempty) {
2949
            if (output_file)
2950
              fprintf(output_file, "%c", empty_sqs[nempty]);
2951
            else
2952
              sprintf(initial_position + strlen(initial_position), "%c",
2953
                  empty_sqs[nempty]);
2954
            nempty = 0;
2955
          }
2956
          if (output_file)
2957
            fprintf(output_file, "%c",
2958
                translate[PcOnSq((rank << 3) + file) + 6]);
2959
          else
2960
            sprintf(initial_position + strlen(initial_position), "%c",
2961
                translate[PcOnSq((rank << 3) + file) + 6]);
2962
        } else
2963
          nempty++;
2964
      }
2965
      if (empty_sqs[nempty]) {
2966
        if (output_file)
2967
          fprintf(output_file, "%c", empty_sqs[nempty]);
2968
        else
2969
          sprintf(initial_position + strlen(initial_position), "%c",
2970
              empty_sqs[nempty]);
2971
      }
2972
      if (rank != RANK1) {
2973
        if (output_file)
2974
          fprintf(output_file, "/");
2975
        else
108 pmbaty 2976
          sprintf(initial_position + strlen(initial_position), "/");
33 pmbaty 2977
      }
2978
    }
2979
    if (output_file)
2980
      fprintf(output_file, " %c ", (game_wtm) ? 'w' : 'b');
2981
    else
108 pmbaty 2982
      sprintf(initial_position + strlen(initial_position), " %c ",
2983
          (game_wtm) ? 'w' : 'b');
33 pmbaty 2984
    if (Castle(0, white) & 1) {
2985
      if (output_file)
2986
        fprintf(output_file, "K");
2987
      else
108 pmbaty 2988
        sprintf(initial_position + strlen(initial_position), "K");
33 pmbaty 2989
    }
2990
    if (Castle(0, white) & 2) {
2991
      if (output_file)
2992
        fprintf(output_file, "Q");
2993
      else
108 pmbaty 2994
        sprintf(initial_position + strlen(initial_position), "Q");
33 pmbaty 2995
    }
2996
    if (Castle(0, black) & 1) {
2997
      if (output_file)
2998
        fprintf(output_file, "k");
2999
      else
108 pmbaty 3000
        sprintf(initial_position + strlen(initial_position), "k");
33 pmbaty 3001
    }
3002
    if (Castle(0, black) & 2) {
3003
      if (output_file)
3004
        fprintf(output_file, "q");
3005
      else
108 pmbaty 3006
        sprintf(initial_position + strlen(initial_position), "q");
33 pmbaty 3007
    }
3008
    if (!Castle(0, white) && !Castle(0, black)) {
3009
      if (output_file)
3010
        fprintf(output_file, " -");
3011
      else
108 pmbaty 3012
        sprintf(initial_position + strlen(initial_position), " -");
33 pmbaty 3013
    }
3014
    if (EnPassant(0)) {
3015
      if (output_file)
3016
        fprintf(output_file, " %c%c", File(EnPassant(0)) + 'a',
3017
            Rank(EnPassant(0)) + '1');
3018
      else
3019
        sprintf(initial_position + strlen(initial_position), " %c%c",
3020
            File(EnPassant(0)) + 'a', Rank(EnPassant(0)) + '1');
3021
    } else {
3022
      if (output_file)
3023
        fprintf(output_file, " -");
3024
      else
108 pmbaty 3025
        sprintf(initial_position + strlen(initial_position), " -");
33 pmbaty 3026
    }
3027
    if (output_file)
3028
      fprintf(output_file, "\n");
3029
    if (output_file && output_file != stdout) {
3030
      fprintf(output_file, "exit\n");
3031
      fclose(output_file);
3032
    }
3033
    if (output_file)
3034
      printf("FEN save complete.\n");
3035
  }
3036
/*
3037
 ************************************************************
3038
 *                                                          *
3039
 *  "scale" command is used for tuning.  We modify this to  *
3040
 *  scale some scoring value(s) by a percentage that can    *
3041
 *  be either positive or negative.                         *
3042
 *                                                          *
3043
 ************************************************************
3044
 */
3045
  else if (!strcmp("scale", *args)) {
3046
    scale = atoi(args[1]);
3047
  }
3048
/*
3049
 ************************************************************
3050
 *                                                          *
3051
 *  "score" command displays static evaluation of the       *
3052
 *  current board position.                                 *
3053
 *                                                          *
3054
 ************************************************************
3055
 */
3056
  else if (OptionMatch("score", *args)) {
108 pmbaty 3057
    int phase, s, tw, tb, mgb, mgw, egb, egw, trop[2];
33 pmbaty 3058
 
3059
    if (thinking || pondering)
3060
      return 2;
108 pmbaty 3061
    memset((void *) &(tree->pawn_score), 0, sizeof(tree->pawn_score));
3062
    Print(32, "note: scores are for the white side\n");
3063
    Print(32, "                       ");
3064
    Print(32, " +-----------white----------+");
3065
    Print(32, "-----------black----------+\n");
33 pmbaty 3066
    tree->score_mg = 0;
3067
    tree->score_eg = 0;
3068
    mgb = tree->score_mg;
3069
    EvaluateMaterial(tree, game_wtm);
3070
    mgb = tree->score_mg - mgb;
108 pmbaty 3071
    Print(32, "material.......%s", DisplayEvaluation(mgb, 1));
3072
    Print(32, "  |    comp     mg      eg   |");
3073
    Print(32, "    comp     mg      eg   |\n");
33 pmbaty 3074
    root_wtm = Flip(game_wtm);
3075
    tree->status[1] = tree->status[0];
3076
    s = Evaluate(tree, 1, game_wtm, -99999, 99999);
108 pmbaty 3077
    trop[black] = tree->tropism[black];
3078
    trop[white] = tree->tropism[white];
33 pmbaty 3079
    if (!game_wtm)
3080
      s = -s;
3081
    tree->score_mg = 0;
3082
    tree->score_eg = 0;
3083
    phase =
3084
        Min(62, TotalPieces(white, occupied) + TotalPieces(black, occupied));
3085
    tree->pawn_score.score_mg = 0;
3086
    tree->pawn_score.score_eg = 0;
3087
    mgb = tree->pawn_score.score_mg;
3088
    egb = tree->pawn_score.score_eg;
3089
    EvaluatePawns(tree, black);
3090
    mgb = tree->pawn_score.score_mg - mgb;
3091
    egb = tree->pawn_score.score_eg - egb;
3092
    mgw = tree->pawn_score.score_mg;
3093
    egw = tree->pawn_score.score_eg;
3094
    EvaluatePawns(tree, white);
3095
    mgw = tree->pawn_score.score_mg - mgw;
3096
    egw = tree->pawn_score.score_eg - egw;
3097
    tb = (mgb * phase + egb * (62 - phase)) / 62;
3098
    tw = (mgw * phase + egw * (62 - phase)) / 62;
108 pmbaty 3099
    Print(32, "pawns..........%s  |", DisplayEvaluation(tb + tw, 1));
3100
    Print(32, " %s", DisplayEvaluation(tw, 1));
3101
    Print(32, " %s", DisplayEvaluation(mgw, 1));
3102
    Print(32, " %s  |", DisplayEvaluation(egw, 1));
3103
    Print(32, " %s", DisplayEvaluation(tb, 1));
3104
    Print(32, " %s", DisplayEvaluation(mgb, 1));
3105
    Print(32, " %s  |\n", DisplayEvaluation(egb, 1));
33 pmbaty 3106
    mgb = tree->score_mg;
3107
    egb = tree->score_eg;
3108
    EvaluatePassedPawns(tree, black, game_wtm);
3109
    mgb = tree->score_mg - mgb;
3110
    egb = tree->score_eg - egb;
3111
    mgw = tree->score_mg;
3112
    egw = tree->score_eg;
3113
    EvaluatePassedPawns(tree, white, game_wtm);
3114
    mgw = tree->score_mg - mgw;
3115
    egw = tree->score_eg - egw;
3116
    tb = (mgb * phase + egb * (62 - phase)) / 62;
3117
    tw = (mgw * phase + egw * (62 - phase)) / 62;
108 pmbaty 3118
    Print(32, "passed pawns...%s  |", DisplayEvaluation(tb + tw, 1));
3119
    Print(32, " %s", DisplayEvaluation(tw, 1));
3120
    Print(32, " %s", DisplayEvaluation(mgw, 1));
3121
    Print(32, " %s  |", DisplayEvaluation(egw, 1));
3122
    Print(32, " %s", DisplayEvaluation(tb, 1));
3123
    Print(32, " %s", DisplayEvaluation(mgb, 1));
3124
    Print(32, " %s  |\n", DisplayEvaluation(egb, 1));
33 pmbaty 3125
    mgb = tree->score_mg;
3126
    egb = tree->score_eg;
3127
    EvaluateKnights(tree, black);
3128
    mgb = tree->score_mg - mgb;
3129
    egb = tree->score_eg - egb;
3130
    mgw = tree->score_mg;
3131
    egw = tree->score_eg;
3132
    EvaluateKnights(tree, white);
3133
    mgw = tree->score_mg - mgw;
3134
    egw = tree->score_eg - egw;
3135
    tb = (mgb * phase + egb * (62 - phase)) / 62;
3136
    tw = (mgw * phase + egw * (62 - phase)) / 62;
108 pmbaty 3137
    Print(32, "knights........%s  |", DisplayEvaluation(tb + tw, 1));
3138
    Print(32, " %s", DisplayEvaluation(tw, 1));
3139
    Print(32, " %s", DisplayEvaluation(mgw, 1));
3140
    Print(32, " %s  |", DisplayEvaluation(egw, 1));
3141
    Print(32, " %s", DisplayEvaluation(tb, 1));
3142
    Print(32, " %s", DisplayEvaluation(mgb, 1));
3143
    Print(32, " %s  |\n", DisplayEvaluation(egb, 1));
33 pmbaty 3144
    mgb = tree->score_mg;
3145
    egb = tree->score_eg;
3146
    EvaluateBishops(tree, black);
3147
    mgb = tree->score_mg - mgb;
3148
    egb = tree->score_eg - egb;
3149
    mgw = tree->score_mg;
3150
    egw = tree->score_eg;
3151
    EvaluateBishops(tree, white);
3152
    mgw = tree->score_mg - mgw;
3153
    egw = tree->score_eg - egw;
3154
    tb = (mgb * phase + egb * (62 - phase)) / 62;
3155
    tw = (mgw * phase + egw * (62 - phase)) / 62;
108 pmbaty 3156
    Print(32, "bishops........%s  |", DisplayEvaluation(tb + tw, 1));
3157
    Print(32, " %s", DisplayEvaluation(tw, 1));
3158
    Print(32, " %s", DisplayEvaluation(mgw, 1));
3159
    Print(32, " %s  |", DisplayEvaluation(egw, 1));
3160
    Print(32, " %s", DisplayEvaluation(tb, 1));
3161
    Print(32, " %s", DisplayEvaluation(mgb, 1));
3162
    Print(32, " %s  |\n", DisplayEvaluation(egb, 1));
33 pmbaty 3163
    mgb = tree->score_mg;
3164
    egb = tree->score_eg;
3165
    EvaluateRooks(tree, black);
3166
    mgb = tree->score_mg - mgb;
3167
    egb = tree->score_eg - egb;
3168
    mgw = tree->score_mg;
3169
    egw = tree->score_eg;
3170
    EvaluateRooks(tree, white);
3171
    mgw = tree->score_mg - mgw;
3172
    egw = tree->score_eg - egw;
3173
    tb = (mgb * phase + egb * (62 - phase)) / 62;
3174
    tw = (mgw * phase + egw * (62 - phase)) / 62;
108 pmbaty 3175
    Print(32, "rooks..........%s  |", DisplayEvaluation(tb + tw, 1));
3176
    Print(32, " %s", DisplayEvaluation(tw, 1));
3177
    Print(32, " %s", DisplayEvaluation(mgw, 1));
3178
    Print(32, " %s  |", DisplayEvaluation(egw, 1));
3179
    Print(32, " %s", DisplayEvaluation(tb, 1));
3180
    Print(32, " %s", DisplayEvaluation(mgb, 1));
3181
    Print(32, " %s  |\n", DisplayEvaluation(egb, 1));
33 pmbaty 3182
    mgb = tree->score_mg;
3183
    egb = tree->score_eg;
3184
    EvaluateQueens(tree, black);
3185
    mgb = tree->score_mg - mgb;
3186
    egb = tree->score_eg - egb;
3187
    mgw = tree->score_mg;
3188
    egw = tree->score_eg;
3189
    EvaluateQueens(tree, white);
3190
    mgw = tree->score_mg - mgw;
3191
    egw = tree->score_eg - egw;
3192
    tb = (mgb * phase + egb * (62 - phase)) / 62;
3193
    tw = (mgw * phase + egw * (62 - phase)) / 62;
108 pmbaty 3194
    Print(32, "queens.........%s  |", DisplayEvaluation(tb + tw, 1));
3195
    Print(32, " %s", DisplayEvaluation(tw, 1));
3196
    Print(32, " %s", DisplayEvaluation(mgw, 1));
3197
    Print(32, " %s  |", DisplayEvaluation(egw, 1));
3198
    Print(32, " %s", DisplayEvaluation(tb, 1));
3199
    Print(32, " %s", DisplayEvaluation(mgb, 1));
3200
    Print(32, " %s  |\n", DisplayEvaluation(egb, 1));
3201
    tree->tropism[black] = trop[black];
3202
    tree->tropism[white] = trop[white];
33 pmbaty 3203
    mgb = tree->score_mg;
3204
    egb = tree->score_eg;
108 pmbaty 3205
    EvaluateKing(tree, 1, black);
33 pmbaty 3206
    mgb = tree->score_mg - mgb;
3207
    egb = tree->score_eg - egb;
3208
    mgw = tree->score_mg;
3209
    egw = tree->score_eg;
108 pmbaty 3210
    EvaluateKing(tree, 1, white);
33 pmbaty 3211
    mgw = tree->score_mg - mgw;
3212
    egw = tree->score_eg - egw;
3213
    tb = (mgb * phase + egb * (62 - phase)) / 62;
3214
    tw = (mgw * phase + egw * (62 - phase)) / 62;
108 pmbaty 3215
    Print(32, "kings..........%s  |", DisplayEvaluation(tb + tw, 1));
3216
    Print(32, " %s", DisplayEvaluation(tw, 1));
3217
    Print(32, " %s", DisplayEvaluation(mgw, 1));
3218
    Print(32, " %s  |", DisplayEvaluation(egw, 1));
3219
    Print(32, " %s", DisplayEvaluation(tb, 1));
3220
    Print(32, " %s", DisplayEvaluation(mgb, 1));
3221
    Print(32, " %s  |\n", DisplayEvaluation(egb, 1));
33 pmbaty 3222
    mgb = tree->score_mg;
3223
    egb = tree->score_eg;
108 pmbaty 3224
    EvaluateCastling(tree, 1, black);
33 pmbaty 3225
    mgb = tree->score_mg - mgb;
3226
    egb = tree->score_eg - egb;
3227
    mgw = tree->score_mg;
3228
    egw = tree->score_eg;
108 pmbaty 3229
    EvaluateCastling(tree, 1, white);
33 pmbaty 3230
    mgw = tree->score_mg - mgw;
3231
    egw = tree->score_eg - egw;
3232
    tb = (mgb * phase + egb * (62 - phase)) / 62;
3233
    tw = (mgw * phase + egw * (62 - phase)) / 62;
108 pmbaty 3234
    Print(32, "castling.......%s  |", DisplayEvaluation(tb + tw, 1));
3235
    Print(32, " %s", DisplayEvaluation(tw, 1));
3236
    Print(32, " %s", DisplayEvaluation(mgw, 1));
3237
    Print(32, " %s  |", DisplayEvaluation(egw, 1));
3238
    Print(32, " %s", DisplayEvaluation(tb, 1));
3239
    Print(32, " %s", DisplayEvaluation(mgb, 1));
3240
    Print(32, " %s  |\n", DisplayEvaluation(egb, 1));
33 pmbaty 3241
    egb = tree->score_eg;
3242
    if ((TotalPieces(white, occupied) == 0 && tree->pawn_score.passed[black])
3243
        || (TotalPieces(black, occupied) == 0 &&
3244
            tree->pawn_score.passed[white]))
3245
      EvaluatePassedPawnRaces(tree, game_wtm);
3246
    egb = tree->score_eg - egb;
108 pmbaty 3247
    Print(32, "pawn races.....%s", DisplayEvaluation(egb, 1));
3248
    Print(32, "  +--------------------------+--------------------------+\n");
3249
    Print(32, "total..........%s\n", DisplayEvaluation(s, 1));
33 pmbaty 3250
  }
3251
/*
3252
 ************************************************************
3253
 *                                                          *
108 pmbaty 3254
 *  "screen" command runs runs through a test suite of      *
3255
 *  positions and culls any where a search returns a value  *
3256
 *  outside the margin given to the screen command.         *
3257
 *                                                          *
3258
 ************************************************************
3259
 */
3260
  else if (OptionMatch("screen", *args)) {
3261
    int margin = 9999999, save_noise, save_display;
3262
 
3263
    nargs = ReadParse(buffer, args, " \t;=");
3264
    if (thinking || pondering)
3265
      return 2;
3266
    if (nargs < 3) {
3267
      printf("usage:  screen <filename> score-margin\n");
3268
      return 1;
3269
    }
3270
    save_noise = noise_level;
3271
    save_display = display_options;
3272
    early_exit = 99;
3273
    margin = atoi(args[2]);
3274
    noise_level = 99999999;
3275
    display_options = 2048;
3276
    Test(args[1], 0, 1, margin);
3277
    noise_level = save_noise;
3278
    display_options = save_display;
3279
    ponder_move = 0;
3280
    last_pv.pathd = 0;
3281
    last_pv.pathl = 0;
3282
  }
3283
/*
3284
 ************************************************************
3285
 *                                                          *
33 pmbaty 3286
 *  "sd" command sets a specific search depth to control    *
3287
 *  the tree search depth.                                  *
3288
 *                                                          *
3289
 ************************************************************
3290
 */
3291
  else if (OptionMatch("sd", *args)) {
3292
    if (nargs < 2) {
3293
      printf("usage:  sd <depth>\n");
3294
      return 1;
3295
    }
3296
    search_depth = atoi(args[1]);
108 pmbaty 3297
    Print(32, "search depth set to %d.\n", search_depth);
33 pmbaty 3298
  }
3299
/*
3300
 ************************************************************
3301
 *                                                          *
108 pmbaty 3302
 *  "search" command sets a specific move for the search    *
3303
 *  to analyze, ignoring all others completely.             *
3304
 *                                                          *
3305
 ************************************************************
3306
 */
3307
  else if (OptionMatch("search", *args)) {
3308
    if (thinking || pondering)
3309
      return 2;
3310
    if (nargs < 2) {
3311
      printf("usage:  search <move>\n");
3312
      return 1;
3313
    }
3314
    search_move = InputMove(tree, 0, game_wtm, 0, 0, args[1]);
3315
    if (!search_move)
3316
      search_move = InputMove(tree, 0, Flip(game_wtm), 0, 0, args[1]);
3317
    if (!search_move)
3318
      printf("illegal move.\n");
3319
  }
3320
/*
3321
 ************************************************************
3322
 *                                                          *
3323
 *  "setboard" command sets the board to a specific         *
3324
 *  position for analysis by the program.                   *
3325
 *                                                          *
3326
 ************************************************************
3327
 */
3328
  else if (OptionMatch("setboard", *args)) {
3329
    if (thinking || pondering)
3330
      return 2;
3331
    nargs = ReadParse(buffer, args, " \t;=");
3332
    if (nargs < 3) {
3333
      printf("usage:  setboard <fen>\n");
3334
      return 1;
3335
    }
3336
    SetBoard(tree, nargs - 1, args + 1, 0);
3337
    move_number = 1;
3338
    if (!game_wtm) {
3339
      game_wtm = 1;
3340
      Pass();
3341
    }
3342
    ponder_move = 0;
3343
    last_pv.pathd = 0;
3344
    last_pv.pathl = 0;
3345
    over = 0;
3346
    strcpy(buffer, "savepos *");
3347
    Option(tree);
3348
  } else if (StrCnt(*args, '/') > 3) {
3349
    if (thinking || pondering)
3350
      return 2;
3351
    nargs = ReadParse(buffer, args, " \t;=");
3352
    SetBoard(tree, nargs, args, 0);
3353
    move_number = 1;
3354
    if (!game_wtm) {
3355
      game_wtm = 1;
3356
      Pass();
3357
    }
3358
    ponder_move = 0;
3359
    last_pv.pathd = 0;
3360
    last_pv.pathl = 0;
3361
    over = 0;
3362
    strcpy(buffer, "savepos *");
3363
    Option(tree);
3364
  }
3365
/*
3366
 ************************************************************
3367
 *                                                          *
3368
 *  "settc" command is used to reset the time controls      *
3369
 *  after a complete restart.                               *
3370
 *                                                          *
3371
 ************************************************************
3372
 */
3373
  else if (OptionMatch("settc", *args)) {
3374
    if (thinking || pondering)
3375
      return 2;
3376
    if (nargs < 4) {
3377
      printf("usage:  settc <wmoves> <wtime> <bmoves> <btime>\n");
3378
      return 1;
3379
    }
3380
    tc_moves_remaining[white] = atoi(args[1]);
3381
    tc_time_remaining[white] = ParseTime(args[2]) * 6000;
3382
    tc_moves_remaining[black] = atoi(args[3]);
3383
    tc_time_remaining[black] = ParseTime(args[4]) * 6000;
3384
    Print(32, "time remaining: %s (white).\n",
3385
        DisplayTime(tc_time_remaining[white]));
3386
    Print(32, "time remaining: %s (black).\n",
3387
        DisplayTime(tc_time_remaining[black]));
3388
    if (tc_sudden_death != 1) {
3389
      Print(32, "%d moves to next time control (white)\n",
3390
          tc_moves_remaining[white]);
3391
      Print(32, "%d moves to next time control (black)\n",
3392
          tc_moves_remaining[black]);
3393
    } else
3394
      Print(32, "Sudden-death time control in effect\n");
3395
    TimeSet(999);
3396
  }
3397
/*
3398
 ************************************************************
3399
 *                                                          *
33 pmbaty 3400
 *  "show" command enables/disables whether or not we want  *
3401
 *  show book information as the game is played.            *
3402
 *                                                          *
3403
 ************************************************************
3404
 */
3405
  else if (OptionMatch("show", *args)) {
3406
    if (nargs < 2) {
3407
      printf("usage:  show book\n");
3408
      return 1;
3409
    }
3410
    if (OptionMatch("book", args[1])) {
3411
      show_book = !show_book;
3412
      if (show_book)
108 pmbaty 3413
        Print(32, "show book statistics\n");
33 pmbaty 3414
      else
108 pmbaty 3415
        Print(32, "don't show book statistics\n");
33 pmbaty 3416
    }
3417
  }
3418
/*
3419
 ************************************************************
3420
 *                                                          *
3421
 *  "skill" command sets a value from 1-100 that affects    *
3422
 *  Crafty's playing skill level.  100 => max skill, 1 =>   *
3423
 *  minimal skill.  This is used to reduce the chess        *
3424
 *  knowledge usage, along with other things.               *
3425
 *                                                          *
3426
 ************************************************************
3427
 */
3428
#if defined(SKILL)
3429
  else if (OptionMatch("skill", *args)) {
3430
    if (nargs < 2) {
3431
      printf("usage:  skill <1-100>\n");
3432
      return 1;
3433
    }
108 pmbaty 3434
    if (skill != 100)
33 pmbaty 3435
      printf("ERROR:  skill can only be changed one time in a game\n");
108 pmbaty 3436
    else {
33 pmbaty 3437
      skill = atoi(args[1]);
3438
      if (skill < 1 || skill > 100) {
3439
        printf("ERROR: skill range is 1-100 only\n");
3440
        skill = 100;
3441
      }
108 pmbaty 3442
      Print(32, "skill level set to %d%%\n", skill);
3443
      null_depth = (null_depth * skill + 50) / 100;
3444
      if (skill < 100)
3445
        null_divisor = null_divisor + 2 * (100 - skill) / 10;
3446
      check_depth = (check_depth * skill + 50) / 100;
3447
      LMR_min = (LMR_min * skill + 50) / 100;
3448
      LMR_max = (LMR_max * skill + 50) / 100;
3449
      InitializeReductions();
33 pmbaty 3450
    }
3451
  }
3452
#endif
3453
/*
3454
 ************************************************************
3455
 *                                                          *
3456
 *   "smp" command is used to tune the various SMP search   *
3457
 *   parameters.                                            *
3458
 *                                                          *
108 pmbaty 3459
 *   "smpaffinity" command is used to enable (>= 0) and to  *
3460
 *   disable smp processor affinity (off).  If you try to   *
3461
 *   run two instances of Crafty on the same machine, ONE   *
3462
 *   them (if not both) need to have processor affinity     *
3463
 *   disabled or else you can use the smpaffinity=<n> to    *
3464
 *   prevent processor conflicts.  If you use a 32 core     *
3465
 *   machine, and you want to run two instances of Crafty,  *
3466
 *   use smpaffinity=0 on one, and smpaffinity=16 on the    *
3467
 *   other.  The first will bind to processors 0-15, and    *
3468
 *   the second will bind to processors 16-31.              *
3469
 *                                                          *
33 pmbaty 3470
 *   "smpgroup" command is used to control how many threads *
3471
 *   may work together at any point in the tree.  The       *
3472
 *   usual default is 6, but this might be reduced on a     *
3473
 *   machine with a large number of processors.  It should  *
3474
 *   be tested, of course.                                  *
3475
 *                                                          *
3476
 *   "smpmin" sets the minimum depth the search can split   *
3477
 *   at to keep it from splitting too near the leaves.      *
3478
 *                                                          *
3479
 *   "smpmt" command is used to set the maximum number of   *
3480
 *   parallel threads to use, assuming that Crafty was      *
3481
 *   compiled with -DSMP.  This value can not be set        *
3482
 *   larger than the compiled-in -DCPUS=n value.            *
3483
 *                                                          *
3484
 *   "smpnice" command turns on "nice" mode where idle      *
3485
 *   processors are terminated between searches to avoid    *
3486
 *   burning CPU time in the idle loop.                     *
3487
 *                                                          *
108 pmbaty 3488
 *   "smpnuma" command enables NUMA mode which distributes  *
3489
 *   hash tables across all NUMA nodes evenly.  If your     *
3490
 *   machine is not NUMA, or only has one socket (node) you *
3491
 *   should set this to zero as it will be slightly more    *
3492
 *   efficient when you change hash sizes.                  *
3493
 *                                                          *
33 pmbaty 3494
 *   "smproot" command is used to enable (1) or disable (0) *
3495
 *   splitting the tree at the root (ply=1).  Splitting at  *
3496
 *   the root is more efficient, but might slow finding the *
3497
 *   move in some test positions.                           *
3498
 *                                                          *
108 pmbaty 3499
 *   "smpgsd" sets the minimum depth remaining at which a   *
3500
 *   gratuitous split can be done.                          *
33 pmbaty 3501
 *                                                          *
108 pmbaty 3502
 *   "smpgsl" sets the maximum number of gratuitous splits  *
3503
 *   per thread.  This only counts splits that have not yet *
3504
 *   been joined.                                           *
3505
 *                                                          *
33 pmbaty 3506
 ************************************************************
3507
 */
108 pmbaty 3508
  else if (OptionMatch("smpaffinity", *args)) {
33 pmbaty 3509
    if (nargs < 2) {
108 pmbaty 3510
      printf("usage:  smpaffinity <0/1>\n");
3511
      return 1;
3512
    }
3513
    if (!strcmp(args[1], "off"))
3514
      smp_affinity = -1;
3515
    else
3516
      smp_affinity = atoi(args[1]);
3517
    if (smp_affinity >= 0)
3518
      Print(32, "smp processor affinity enabled.\n");
3519
    else
3520
      Print(32, "smp processor affinity disabled.\n");
3521
  } else if (OptionMatch("smpmin", *args)) {
3522
    if (nargs < 2) {
33 pmbaty 3523
      printf("usage:  smpmin <depth>\n");
3524
      return 1;
3525
    }
3526
    smp_min_split_depth = atoi(args[1]);
108 pmbaty 3527
    Print(32, "minimum thread depth set to %d.\n", smp_min_split_depth);
33 pmbaty 3528
  } else if (OptionMatch("smpgroup", *args)) {
3529
    if (nargs < 2) {
3530
      printf("usage:  smpgroup <threads>\n");
3531
      return 1;
3532
    }
3533
    smp_split_group = atoi(args[1]);
108 pmbaty 3534
    Print(32, "maximum thread group size set to %d.\n", smp_split_group);
33 pmbaty 3535
  } else if (OptionMatch("smpmt", *args) || OptionMatch("mt", *args)
3536
      || OptionMatch("cores", *args)) {
3537
    int proc;
3538
 
3539
    if (nargs < 2) {
3540
      printf("usage:  smpmt=<threads>\n");
3541
      return 1;
3542
    }
3543
    if (thinking || pondering)
3544
      return 3;
3545
    allow_cores = 0;
108 pmbaty 3546
    if (xboard)
3547
      Print(4095, "Warning--  xboard 'cores' option disabled\n");
33 pmbaty 3548
    smp_max_threads = atoi(args[1]);
3549
    if (smp_max_threads > CPUS) {
3550
      Print(4095, "ERROR - Crafty was compiled with CPUS=%d.", CPUS);
3551
      Print(4095, "  mt can not exceed this value.\n");
3552
      smp_max_threads = CPUS;
3553
    }
108 pmbaty 3554
    if (smp_max_threads == 1) {
3555
      Print(4095, "ERROR - max threads can be set to zero (0) to");
3556
      Print(4095, " disable parallel search, otherwise it must be > 1.\n");
3557
      smp_max_threads = 0;
3558
    }
33 pmbaty 3559
    if (smp_max_threads)
108 pmbaty 3560
      Print(32, "max threads set to %d.\n", smp_max_threads);
33 pmbaty 3561
    else
108 pmbaty 3562
      Print(32, "parallel threads disabled.\n");
33 pmbaty 3563
    for (proc = 1; proc < CPUS; proc++)
108 pmbaty 3564
      if (proc >= (int) smp_max_threads) // Pierre-Marie Baty -- added type cast
3565
        thread[proc].terminate = 1;
33 pmbaty 3566
  } else if (OptionMatch("smpnice", *args)) {
3567
    if (nargs < 2) {
3568
      printf("usage:  smpnice 0|1\n");
3569
      return 1;
3570
    }
3571
    smp_nice = atoi(args[1]);
3572
    if (smp_nice)
108 pmbaty 3573
      Print(32, "SMP terminate extra threads when idle.\n");
33 pmbaty 3574
    else
108 pmbaty 3575
      Print(32, "SMP keep extra threads spinning when idle.\n");
3576
  } else if (OptionMatch("smpnuma", *args)) {
3577
    if (nargs < 2) {
3578
      printf("usage:  smpnuma 0|1\n");
3579
      return 1;
3580
    }
3581
    smp_numa = atoi(args[1]);
3582
    if (smp_numa)
3583
      Print(32, "SMP NUMA mode enabled.\n");
3584
    else
3585
      Print(32, "SMP NUMA mode disabled.\n");
33 pmbaty 3586
  } else if (OptionMatch("smproot", *args)) {
3587
    if (nargs < 2) {
3588
      printf("usage:  smproot 0|1\n");
3589
      return 1;
3590
    }
3591
    smp_split_at_root = atoi(args[1]);
3592
    if (smp_split_at_root)
108 pmbaty 3593
      Print(32, "SMP search split at ply >= 1.\n");
33 pmbaty 3594
    else
108 pmbaty 3595
      Print(32, "SMP search split at ply > 1.\n");
3596
  } else if (OptionMatch("smpgsl", *args)) {
33 pmbaty 3597
    if (nargs < 2) {
108 pmbaty 3598
      printf("usage:  smpgsl <n>\n");
33 pmbaty 3599
      return 1;
3600
    }
108 pmbaty 3601
    smp_gratuitous_limit = atoi(args[1]);
3602
    Print(32, "maximum gratuitous splits allowed %d.\n",
3603
        smp_gratuitous_limit);
3604
  } else if (OptionMatch("smpgsd", *args)) {
3605
    if (nargs < 2) {
3606
      printf("usage:  smpgsd <nodes>\n");
3607
      return 1;
3608
    }
3609
    smp_gratuitous_depth = atoi(args[1]);
3610
    Print(32, "gratuitous split min depth %d.\n", smp_gratuitous_depth);
33 pmbaty 3611
  }
3612
/*
3613
 ************************************************************
3614
 *                                                          *
3615
 *  "sn" command sets a specific number of nodes to search  *
3616
 *  before stopping.  Note:  this requires -DNODES as an    *
3617
 *  option when building Crafty.                            *
3618
 *                                                          *
3619
 ************************************************************
3620
 */
3621
  else if (OptionMatch("sn", *args)) {
3622
    if (nargs < 2) {
3623
      printf("usage:  sn <nodes>\n");
3624
      return 1;
3625
    }
3626
    search_nodes = atoi(args[1]);
108 pmbaty 3627
    Print(32, "search nodes set to %" PRIu64 ".\n", search_nodes);
33 pmbaty 3628
    ponder = 0;
3629
  }
3630
/*
3631
 ************************************************************
3632
 *                                                          *
3633
 *  "speech" command turns speech on/off.                   *
3634
 *                                                          *
3635
 ************************************************************
3636
 */
3637
  else if (OptionMatch("speech", *args)) {
3638
    if (nargs < 2) {
3639
      printf("usage:  speech on|off\n");
3640
      return 1;
3641
    }
3642
    if (!strcmp(args[1], "on"))
3643
      speech = 1;
3644
    else if (!strcmp(args[1], "off"))
3645
      speech = 0;
3646
    if (speech)
3647
      Print(4095, "Audio output enabled\n");
3648
    else
3649
      Print(4095, "Audio output disabled\n");
3650
  }
3651
/*
3652
 ************************************************************
3653
 *                                                          *
3654
 *  "st" command sets a specific search time to control the *
3655
 *  tree search time.                                       *
3656
 *                                                          *
3657
 ************************************************************
3658
 */
108 pmbaty 3659
  else if (OptionMatch("st", *args)) {
33 pmbaty 3660
    if (nargs < 2) {
3661
      printf("usage:  st <time>\n");
3662
      return 1;
3663
    }
3664
    search_time_limit = (int) (atof(args[1]) * 100); // Pierre-Marie Baty -- added type cast
108 pmbaty 3665
    Print(32, "search time set to %.2f.\n",
33 pmbaty 3666
        (float) search_time_limit / 100.0);
3667
  }
3668
/*
3669
 ************************************************************
3670
 *                                                          *
3671
 *  "swindle" command turns swindle mode off/on.            *
3672
 *                                                          *
3673
 ************************************************************
3674
 */
3675
  else if (OptionMatch("swindle", *args)) {
3676
    if (!strcmp(args[1], "on"))
3677
      swindle_mode = 1;
3678
    else if (!strcmp(args[1], "off"))
3679
      swindle_mode = 0;
3680
    else
3681
      printf("usage:  swindle on|off\n");
3682
  }
3683
/*
3684
 ************************************************************
3685
 *                                                          *
3686
 *  "tags" command lists the current PGN header tags.       *
3687
 *                                                          *
3688
 ************************************************************
3689
 */
3690
  else if (OptionMatch("tags", *args)) {
3691
    struct tm *timestruct;
3692
    uint64_t secs;
3693
 
3694
    secs = time(0);
3695
    timestruct = localtime((time_t *) & secs);
3696
    printf("[Event \"%s\"]\n", pgn_event);
3697
    printf("[Site \"%s\"]\n", pgn_site);
3698
    printf("[Date \"%4d.%02d.%02d\"]\n", timestruct->tm_year + 1900,
3699
        timestruct->tm_mon + 1, timestruct->tm_mday);
3700
    printf("[Round \"%s\"]\n", pgn_round);
3701
    printf("[White \"%s\"]\n", pgn_white);
3702
    printf("[WhiteElo \"%s\"]\n", pgn_white_elo);
3703
    printf("[Black \"%s\"]\n", pgn_black);
3704
    printf("[BlackElo \"%s\"]\n", pgn_black_elo);
3705
    printf("[Result \"%s\"]\n", pgn_result);
3706
  }
3707
/*
3708
 ************************************************************
3709
 *                                                          *
3710
 *  "test" command runs a test suite of problems and        *
3711
 *  displays results.                                       *
3712
 *                                                          *
3713
 ************************************************************
3714
 */
3715
  else if (OptionMatch("test", *args)) {
108 pmbaty 3716
    FILE *unsolved = NULL;
3717
    int save_noise, save_display;
3718
 
33 pmbaty 3719
    if (thinking || pondering)
3720
      return 2;
108 pmbaty 3721
    nargs = ReadParse(buffer, args, " \t;=");
33 pmbaty 3722
    if (nargs < 2) {
3723
      printf("usage:  test <filename> [exitcnt]\n");
3724
      return 1;
3725
    }
108 pmbaty 3726
    save_noise = noise_level;
3727
    save_display = display_options;
33 pmbaty 3728
    if (nargs > 2)
3729
      early_exit = atoi(args[2]);
108 pmbaty 3730
    if (nargs > 3)
3731
      unsolved = fopen(args[3], "w+");
3732
    Test(args[1], unsolved, 0, 0);
3733
    noise_level = save_noise;
3734
    display_options = save_display;
33 pmbaty 3735
    ponder_move = 0;
3736
    last_pv.pathd = 0;
3737
    last_pv.pathl = 0;
108 pmbaty 3738
    if (unsolved)
3739
      fclose(unsolved);
33 pmbaty 3740
  }
3741
/*
3742
 ************************************************************
3743
 *                                                          *
3744
 *  "time" is used to set the basic search timing controls. *
3745
 *  The general form of the command is as follows:          *
3746
 *                                                          *
3747
 *    time nmoves/ntime/[nmoves/ntime]/[increment]          *
3748
 *                                                          *
3749
 *  nmoves/ntime represents a traditional first time        *
3750
 *  control when nmoves is an integer representing the      *
3751
 *  number of moves and ntime is the total time allowed for *
3752
 *  these moves.  The [optional] nmoves/ntime is a          *
3753
 *  traditional secondary time control.  Increment is a     *
3754
 *  feature related to ics play and emulates the fischer    *
3755
 *  clock where "increment" is added to the time left after *
3756
 *  each move is made.                                      *
3757
 *                                                          *
3758
 *  As an alternative, nmoves can be "sd" which represents  *
3759
 *  a "sudden death" time control of the remainder of the   *
3760
 *  game played in ntime.  The optional secondary time      *
3761
 *  control can be a sudden-death time control, as in the   *
3762
 *  following example:                                      *
3763
 *                                                          *
3764
 *    time 60/30/sd/30                                      *
3765
 *                                                          *
3766
 *  This sets 60 moves in 30 minutes, then game in 30       *
3767
 *  additional minutes.  An increment can be added if       *
3768
 *  desired.                                                *
3769
 *                                                          *
3770
 ************************************************************
3771
 */
3772
  else if (OptionMatch("time", *args)) {
3773
    if (xboard) {
108 pmbaty 3774
      tc_time_remaining[Flip(game_wtm)] = atoi(args[1]);
33 pmbaty 3775
      if (log_file && time_limit > 99)
3776
        fprintf(log_file, "time remaining: %s (Crafty).\n",
108 pmbaty 3777
            DisplayTime(tc_time_remaining[Flip(game_wtm)]));
33 pmbaty 3778
    } else {
3779
      if (thinking || pondering)
3780
        return 2;
3781
      tc_moves = 60;
3782
      tc_time = 180000;
3783
      tc_moves_remaining[white] = 60;
3784
      tc_moves_remaining[black] = 60;
3785
      tc_time_remaining[white] = 180000;
3786
      tc_time_remaining[black] = 180000;
3787
      tc_secondary_moves = 60;
3788
      tc_secondary_time = 180000;
3789
      tc_increment = 0;
3790
      tc_sudden_death = 0;
3791
/*
3792
 first let's pick off the basic time control (moves/minutes)
3793
 */
3794
      if (nargs > 1)
3795
        if (!strcmp(args[1], "sd")) {
3796
          tc_sudden_death = 1;
3797
          tc_moves = 1000;
3798
        }
3799
      if (nargs > 2) {
3800
        tc_moves = atoi(args[1]);
3801
        tc_time = atoi(args[2]) * 100;
3802
      }
3803
/*
3804
 now let's pick off the secondary time control (moves/minutes)
3805
 */
3806
      tc_secondary_time = tc_time;
3807
      tc_secondary_moves = tc_moves;
3808
      if (nargs > 4) {
3809
        if (!strcmp(args[3], "sd")) {
3810
          tc_sudden_death = 2;
3811
          tc_secondary_moves = 1000;
3812
        } else
3813
          tc_secondary_moves = atoi(args[3]);
3814
        tc_secondary_time = atoi(args[4]) * 100;
3815
      }
3816
      if (nargs > 5)
3817
        tc_increment = atoi(args[5]) * 100;
3818
      tc_time_remaining[white] = tc_time;
3819
      tc_time_remaining[black] = tc_time;
3820
      tc_moves_remaining[white] = tc_moves;
3821
      tc_moves_remaining[black] = tc_moves;
3822
      if (!tc_sudden_death) {
108 pmbaty 3823
        Print(32, "%d moves/%d minutes primary time control\n", tc_moves,
33 pmbaty 3824
            tc_time / 100);
108 pmbaty 3825
        Print(32, "%d moves/%d minutes secondary time control\n",
33 pmbaty 3826
            tc_secondary_moves, tc_secondary_time / 100);
3827
        if (tc_increment)
108 pmbaty 3828
          Print(32, "increment %d seconds.\n", tc_increment / 100);
33 pmbaty 3829
      } else if (tc_sudden_death == 1) {
108 pmbaty 3830
        Print(32, " game/%d minutes primary time control\n", tc_time / 100);
33 pmbaty 3831
        if (tc_increment)
108 pmbaty 3832
          Print(32, "increment %d seconds.\n", tc_increment / 100);
33 pmbaty 3833
      } else if (tc_sudden_death == 2) {
108 pmbaty 3834
        Print(32, "%d moves/%d minutes primary time control\n", tc_moves,
33 pmbaty 3835
            tc_time / 100);
108 pmbaty 3836
        Print(32, "game/%d minutes secondary time control\n",
33 pmbaty 3837
            tc_secondary_time / 100);
3838
        if (tc_increment)
108 pmbaty 3839
          Print(32, "increment %d seconds.\n", tc_increment / 100);
33 pmbaty 3840
      }
3841
      tc_time *= 60;
3842
      tc_time_remaining[white] *= 60;
3843
      tc_time_remaining[black] *= 60;
3844
      tc_secondary_time *= 60;
3845
      tc_safety_margin = tc_time / 6;
3846
    }
3847
  }
3848
/*
3849
 ************************************************************
3850
 *                                                          *
3851
 *  "timebook" command is used to adjust Crafty's time      *
3852
 *  usage after it leaves the opening book.  The first      *
3853
 *  value specifies the multiplier for the time added to    *
3854
 *  the first move out of book expressed as a percentage    *
3855
 *  (100 is 100% for example).  The second value specifies  *
3856
 *  the "span" (number of moves) that this multiplier       *
3857
 *  decays over.  For example, "timebook 100 10" says to    *
3858
 *  add 100% of the normal search time for the first move   *
3859
 *  out of book, then 90% for the next, until after 10      *
3860
 *  non-book moves have been played, the percentage has     *
3861
 *  dropped back to 0 where it will stay for the rest of    *
3862
 *  the game.                                               *
3863
 *                                                          *
3864
 ************************************************************
3865
 */
3866
  else if (OptionMatch("timebook", *args)) {
3867
    if (nargs < 3) {
3868
      printf("usage:  timebook <percentage> <move span>\n");
3869
      return 1;
3870
    }
3871
    first_nonbook_factor = atoi(args[1]);
3872
    first_nonbook_span = atoi(args[2]);
3873
    if (first_nonbook_factor < 0 || first_nonbook_factor > 500) {
3874
      Print(4095, "ERROR, factor must be >= 0 and <= 500\n");
3875
      first_nonbook_factor = 0;
3876
    }
3877
    if (first_nonbook_span < 0 || first_nonbook_span > 30) {
3878
      Print(4095, "ERROR, span must be >= 0 and <= 30\n");
3879
      first_nonbook_span = 0;
3880
    }
3881
  }
3882
/*
3883
 ************************************************************
3884
 *                                                          *
3885
 *  "trace" command sets the search trace level which will  *
3886
 *  dump the tree as it is searched.                        *
3887
 *                                                          *
3888
 ************************************************************
3889
 */
3890
  else if (OptionMatch("trace", *args)) {
3891
#if !defined(TRACE)
3892
    printf
3893
        ("Sorry, but I can't display traces unless compiled with -DTRACE\n");
3894
#endif
3895
    if (nargs < 2) {
3896
      printf("usage:  trace <depth>\n");
3897
      return 1;
3898
    }
3899
    trace_level = atoi(args[1]);
3900
    printf("trace=%d\n", trace_level);
3901
  }
3902
/*
3903
 ************************************************************
3904
 *                                                          *
3905
 *  "undo" command backs up 1/2 move, which leaves the      *
3906
 *  opposite side on move. [xboard compatibility]           *
3907
 *                                                          *
3908
 ************************************************************
3909
 */
108 pmbaty 3910
  else if (OptionMatch("undo", *args)) {
33 pmbaty 3911
    if (thinking || pondering)
3912
      return 2;
3913
    if (!game_wtm || move_number != 1) {
3914
      game_wtm = Flip(game_wtm);
3915
      if (Flip(game_wtm))
3916
        move_number--;
108 pmbaty 3917
      sprintf(buffer, "reset %d", move_number);
3918
      Option(tree);
33 pmbaty 3919
    }
3920
  }
3921
/*
108 pmbaty 3922
 ************************************************************
3923
 *                                                          *
3924
 *  "usage" command controls the time usage multiplier      *
3925
 *  factors used in the game  - percentage increase or      *
3926
 *  decrease in time used up front.  Enter a number between *
3927
 *  1 to 100 for the % decrease (negative value) or to      *
3928
 *  increase (positive value) although other time           *
3929
 *  limitation controls may kick in.  This more commonly    *
3930
 *  used in the .craftyrc/crafty.rc file.                   *
3931
 *                                                          *
3932
 ************************************************************
33 pmbaty 3933
 */
3934
  else if (OptionMatch("usage", *args)) {
3935
    if (nargs < 2) {
3936
      printf("usage:  usage <percentage>\n");
3937
      return 1;
3938
    }
3939
    usage_level = atoi(args[1]);
3940
    if (usage_level > 50)
3941
      usage_level = 50;
3942
    else if (usage_level < -50)
3943
      usage_level = -50;
108 pmbaty 3944
    Print(32, "time usage up front set to %d percent increase/(-)decrease.\n",
33 pmbaty 3945
        usage_level);
3946
  }
3947
/*
3948
 ************************************************************
3949
 *                                                          *
3950
 *  "variant" command sets the wild variant being played    *
3951
 *  on a chess server.  [xboard compatibility].             *
3952
 *                                                          *
3953
 ************************************************************
3954
 */
3955
  else if (OptionMatch("variant", *args)) {
3956
    if (thinking || pondering)
3957
      return 2;
3958
    printf("command=[%s]\n", buffer);
3959
    return -1;
3960
  }
3961
/*
3962
 ************************************************************
3963
 *                                                          *
3964
 *  "whisper" command sets whisper mode for ICS.  =1 will   *
3965
 *  whisper mate announcements, =2 will whisper scores and  *
3966
 *  other info, =3 will whisper scores and PV, =4 adds the  *
3967
 *  list of book moves, =5 displays the PV after each       *
3968
 *  iteration completes, and =6 displays the PV each time   *
3969
 *  it changes in an iteration.                             *
3970
 *                                                          *
3971
 ************************************************************
3972
 */
3973
  else if (OptionMatch("whisper", *args)) {
3974
    if (nargs < 2) {
3975
      printf("usage:  whisper <level>\n");
3976
      return 1;
3977
    }
108 pmbaty 3978
    kibitz = 16 + Min(0, atoi(args[1]));
33 pmbaty 3979
  }
3980
/*
3981
 ************************************************************
3982
 *                                                          *
108 pmbaty 3983
 *  "white" command sets white to move (wtm).               *
3984
 *                                                          *
3985
 ************************************************************
3986
 */
3987
  else if (OptionMatch("white", *args)) {
3988
    if (thinking || pondering)
3989
      return 2;
3990
    ponder_move = 0;
3991
    last_pv.pathd = 0;
3992
    last_pv.pathl = 0;
3993
    if (!game_wtm)
3994
      Pass();
3995
    force = 0;
3996
  }
3997
/*
3998
 ************************************************************
3999
 *                                                          *
33 pmbaty 4000
 *  "wild" command sets up an ICS wild position (only 7 at  *
4001
 *  present, but any can be added easily, except for those  *
4002
 *  that Crafty simply can't play (two kings, invisible     *
4003
 *  pieces, etc.)                                           *
4004
 *                                                          *
4005
 ************************************************************
4006
 */
4007
  else if (OptionMatch("wild", *args)) {
4008
    int i;
4009
 
4010
    if (nargs < 2) {
4011
      printf("usage:  wild <value>\n");
4012
      return 1;
4013
    }
4014
    i = atoi(args[1]);
4015
    switch (i) {
4016
      case 7:
108 pmbaty 4017
        strcpy(buffer, "setboard 4k/5ppp/////PPP/3K/ w");
4018
        Option(tree);
33 pmbaty 4019
        break;
4020
      default:
4021
        printf("sorry, only wild7 implemented at present\n");
4022
        break;
4023
    }
4024
  }
4025
/*
4026
 ************************************************************
4027
 *                                                          *
4028
 *  "xboard" command is normally invoked from main() via    *
4029
 *  the xboard command-line option.  It sets proper         *
4030
 *  defaults for Xboard interface requirements.             *
4031
 *                                                          *
4032
 ************************************************************
4033
 */
4034
  else if (OptionMatch("xboard", *args) || OptionMatch("winboard", *args)) {
4035
    if (!xboard) {
4036
      signal(SIGINT, SIG_IGN);
4037
      xboard = 1;
108 pmbaty 4038
      display_options = 2048;
4039
      Print(-1, "\n");
4040
      Print(-1, "tellicsnoalias set 1 Crafty v%s (%d cpus)\n", version, Max(1,
33 pmbaty 4041
              smp_max_threads));
108 pmbaty 4042
      Print(-1, "tellicsnoalias kibitz Hello from Crafty v%s! (%d cpus)\n",
33 pmbaty 4043
          version, Max(1, smp_max_threads));
4044
    }
4045
  }
4046
/*
4047
 ************************************************************
4048
 *                                                          *
4049
 *  "?" command does nothing, but since this is the "move   *
4050
 *  now" keystroke, if Crafty is not searching, this will   *
4051
 *  simply "wave it off" rather than produce an error.      *
4052
 *                                                          *
4053
 ************************************************************
4054
 */
4055
  else if (OptionMatch("?", *args)) {
4056
  }
4057
/*
4058
 ************************************************************
4059
 *                                                          *
4060
 *  unknown command, it must be a move.                     *
4061
 *                                                          *
4062
 ************************************************************
4063
 */
4064
  else
4065
    return 0;
4066
/*
4067
 ************************************************************
4068
 *                                                          *
4069
 *  command executed, return for another.                   *
4070
 *                                                          *
4071
 ************************************************************
4072
 */
4073
  return 1;
4074
}
4075
 
4076
/*
4077
 *******************************************************************************
4078
 *                                                                             *
4079
 *   OptionMatch() is used to recognize user commands.  It requires that the   *
4080
 *   command (text input which is the *2nd parameter* conform to the following *
4081
 *   simple rules:                                                             *
4082
 *                                                                             *
4083
 *     1.  The input must match the command, starting at the left-most         *
4084
 *         character.                                                          *
4085
 *     2.  If the command starts with a sequence of characters that could      *
4086
 *         be interpreted as a chess move as well (re for reset and/or rook    *
4087
 *         to the e-file) then the input must match enough of the command      *
4088
 *         to get past the ambiguity (res would be minimum we will accept      *
4089
 *         for the reset command.)                                             *
4090
 *                                                                             *
4091
 *******************************************************************************
4092
 */
4093
int OptionMatch(char *command, char *input) {
4094
/*
4095
 ************************************************************
4096
 *                                                          *
4097
 *  check for the obvious exact match first.                *
4098
 *                                                          *
4099
 ************************************************************
4100
 */
4101
  if (!strcmp(command, input))
4102
    return 1;
4103
/*
4104
 ************************************************************
4105
 *                                                          *
4106
 *  now use strstr() to see if "input" is in "command." the *
4107
 *  first requirement is that input matches command         *
4108
 *  starting at the very left-most character.               *
4109
 *                                                          *
4110
 ************************************************************
4111
 */
4112
  if (strstr(command, input) == command)
4113
    return 1;
4114
  return 0;
4115
}
108 pmbaty 4116
 
33 pmbaty 4117
void OptionPerft(TREE * RESTRICT tree, int ply, int depth, int wtm) {
108 pmbaty 4118
  unsigned *mv;
33 pmbaty 4119
#if defined(TRACE)
4120
  static char line[256];
4121
  static char move[16], *p[64];
4122
#endif
108 pmbaty 4123
 
33 pmbaty 4124
  tree->last[ply] = GenerateCaptures(tree, ply, wtm, tree->last[ply - 1]);
4125
  for (mv = tree->last[ply - 1]; mv < tree->last[ply]; mv++)
4126
    if (Captured(*mv) == king)
4127
      return;
4128
  tree->last[ply] = GenerateNoncaptures(tree, ply, wtm, tree->last[ply]);
4129
#if defined(TRACE)
4130
  p[1] = line;
4131
#endif
4132
  for (mv = tree->last[ply - 1]; mv < tree->last[ply]; mv++) {
4133
#if defined(TRACE)
108 pmbaty 4134
    strcpy(move, OutputMove(tree, ply, wtm, *mv));
33 pmbaty 4135
#endif
108 pmbaty 4136
    MakeMove(tree, ply, wtm, *mv);
33 pmbaty 4137
#if defined(TRACE)
4138
    if (ply <= trace_level) {
4139
      strcpy(p[ply], move);
108 pmbaty 4140
      strcpy(line + strlen(line), " ");
33 pmbaty 4141
      p[ply + 1] = line + strlen(line);
4142
      if (ply == trace_level)
4143
        printf("%s\n", line);
4144
    }
4145
#endif
4146
    if (depth - 1)
4147
      OptionPerft(tree, ply + 1, depth - 1, Flip(wtm));
4148
    else if (!Check(wtm))
4149
      total_moves++;
108 pmbaty 4150
    UnmakeMove(tree, ply, wtm, *mv);
33 pmbaty 4151
  }
4152
}