#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <signal.h>
#include "chess.h"
#include "data.h"
#if defined(UNIX) || defined(AMIGA)
#  include <unistd.h>
#endif
#include "epdglue.h"

/* last modified 06/08/98 */
/*
********************************************************************************
*                                                                              *
*   Option() is used to handle user input necessary to control/customize the   *
*   program.  it performs all functions excepting chess move input which is    *
*   handled by main().                                                         *
*                                                                              *
********************************************************************************
*/
int Option(TREE *tree)
{
/*
 ----------------------------------------------------------
|                                                          |
|   EPD implementation interface code.  EPD commands can   |
|   not be handled if the program is actually searching in |
|   a real game, and if Crafty is "pondering" this has to  |
|   be stopped.                                            |
|                                                          |
 ----------------------------------------------------------
*/
  nargs=ReadParse(buffer,args," 	;=/");
  if (!nargs) return(1);
  if (initialized) {
    if (EGCommandCheck(buffer)) {
      if (thinking || pondering) return (2);
      else {
        (void) EGCommand(buffer);
        return (1);
      }
    }
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "." ignores "." if it happens to get to this point, if |
|   xboard is running.                                     |
|                                                          |
 ----------------------------------------------------------
*/
  if (OptionMatch(".",*args)) {
    if (xboard) {
      printf("stat01: 0 0 0 0 0\n");
      fflush(stdout);
      return(1);
    }
    else return(0);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "alarm" command turns audible move warning on/off.     |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("alarm",*args)) {
    RestoreGame();
    if (!strcmp(args[1],"on")) audible_alarm=0x07;
    else if (!strcmp(args[1],"off")) audible_alarm=0x00;
    else printf("usage:  alarm on|off\n");
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "analyze" puts crafty in analyze mode, where it reads  |
|   moves in and between moves, computes as though it is   |
|   trying to find the best move to make.  when another    |
|   move is entered, it switches sides and continues.  it  |
|   will never make a move on its own, rather, it will     |
|   continue to analyze until an "exit" command is given.  |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("analyze",*args)) {
    if (thinking || pondering) return(2);
    Analyze();
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "annotate" command is used to read a series of moves   |
|   and analyze the resulting game, producing comments as  |
|   requested by the user.                                 |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("annotate",*args)) {
    if (thinking || pondering) return(2);
    Annotate();
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "ansi" command turns video highlight on/off.           |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("ansi",*args)) {
    if (nargs < 2) printf("usage:  ansi on|off\n");
    if (!strcmp(args[1],"on")) ansi=1;
    else if (!strcmp(args[1],"off")) ansi=0;
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "auto232" enables auto232 mode.  note that there is    |
|   another alias "DR".                                    |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("auto232",*args) || OptionMatch("DR",*args)) {
    if (auto_file) {
      fclose(auto_file);
      auto_file=0;
      auto232=0;
      printf("auto232 disabled\n");
    }
    else {
      auto_file=fopen("PRN", "w");
      auto232=1;
      printf("auto232 enabled\n");
      book_selection_width=3;
      mode=tournament_mode;
    }
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "batch" command disables asynchronous I/O so that a    |
|   stream of commands can be put into a file and they are |
|   not executed instantly.                                |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("batch",*args)) {
    if (!strcmp(args[1],"on")) batch_mode=1;
    else if (!strcmp(args[1],"off")) batch_mode=0;
    else printf("usage:  batch on|off\n");
  }
/*
 ----------------------------------------------------------
|                                                          |
|  "beep" command is ignored. [xboard compatibility]       |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("beep",*args)) {
    return(xboard);
  }
/*
 ----------------------------------------------------------
|                                                          |
|  "bench" runs internal performance benchmark             |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("bench",*args)) {
    Bench();
  }
/*
 ----------------------------------------------------------
|                                                          |
|  "bk"  book command from xboard sends the suggested book |
|  moves.                                                  |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("bk",*args)) {
    printf("\t%s\n\n",book_hint);
    fflush(stdout);
    return(xboard);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "black" command sets black to move (ChangeSide(wtm)).             |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("black",*args)) {
    if (strlen(*args) == 1) return(1);
    if (thinking || pondering) return (2);
    ponder_move=0;
    last_pv.path_iteration_depth=0;
    last_pv.path_length=0;
    if (wtm) Pass();
    force=0;
  }
/*
 ----------------------------------------------------------
|                                                          |
|  "bogus" command is ignored. [xboard compatibility]      |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("bogus",*args)) {
    return(xboard);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "bookw" command updates the book selection weights.    |
|                                                          |
 ----------------------------------------------------------
*/
  else if (!strcmp("bookw",*args)) {
    if (nargs > 1) {
      if (!strcmp("freq",args[1]))
        book_weight_freq=atof(args[2]);
      else if (!strcmp("eval",args[1]))
        book_weight_eval=atof(args[2]);
      else if (!strcmp("learn",args[1]))
        book_weight_learn=atof(args[2]);
    }
    else {
      Print(128,"frequency (freq)..............%4.2f\n",book_weight_freq);
      Print(128,"static evaluation (eval)......%4.2f\n",book_weight_eval);
      Print(128,"learning (learn)..............%4.2f\n",book_weight_learn);
    }
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "book" command updates/creates the opening book file.  |
|                                                          |
 ----------------------------------------------------------
*/
  else if (!strcmp("book",*args)) {
    nargs=ReadParse(buffer,args," 	;");
    BookUp(tree,"book.bin", nargs-1,args+1);
  }
  else if (!strcmp("books",*args)) {
    nargs=ReadParse(buffer,args," 	;");
    BookUp(tree,"books.bin", nargs-1,args+1);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "channel" command behaves just like the whisper        |
|   command, but sends the output to "channel n" instead.  |
|   there is an optional second parameter that will be     |
|   added to the channel tell to indicate what the tell is |
|   connected to, such as when multiple GM games are going |
|   on, so that the comment can be directed to a game.     |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("channel",*args)) {
    int tchannel;

    nargs=ReadParse(buffer,args," 	;");
    if (nargs < 2) {
      printf("usage:  channel <n> [title]\n");
      return(1);
    }
    tchannel=atoi(args[1]);
    if (tchannel) channel=tchannel;
    if (nargs > 1) strcpy(channel_title,args[2]);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "clock" command displays chess clock.                  |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("clock",*args)) {
    if (nargs > 1)
      tc_time_remaining=ParseTime(args[1])*6000;
      if (tc_time_remaining <= tc_operator_time) {
        Print(4095,"ERROR:  remaining time less than operator time\n");
        Print(4095,"ERROR:  resetting operator time to 0:00.\n");
        Print(4095,"ERROR:  use \"operator n\" command to correct after time control\n");
        tc_operator_time=0;
      }
      
    if (nargs > 2)
      tc_time_remaining_opponent=ParseTime(args[2])*6000;
    Print(4095,"time remaining %s (Crafty)",
          DisplayHHMM(tc_time_remaining));
    Print(4095,"  %s (opponent).\n",
          DisplayHHMM(tc_time_remaining_opponent));
    Print(4095,"%d moves to next time control (Crafty)\n",
          tc_moves_remaining);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "display" command displays the chess board.            |
|                                                          |
|   "display" command sets specific display options which  |
|   control how "chatty" the program is.  in the variable  |
|   display_options, the following bits are set/cleared    |
|   based on the option chosen.                            |
|                                                          |
|     1 -> display time for moves.                         |
|     2 -> display variation when it changes.              |
|     4 -> display variation at end of iteration.          |
|     8 -> display basic search statistics.                |
|    16 -> display extended search statistics.             |
|    32 -> display root moves as they are searched.        |
|    64 -> display move numbers in the PV output.          |
|   128 -> display general informational messages.         |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("display",*args)) {
    int i;
    if (nargs > 1) do {
      if (OptionMatch("time",args[1])) {
        display_options|=1;
        Print(128,"display time for moves played in game.\n");
      }
      else if (OptionMatch("notime",args[1])) {
        display_options&=4095-1;
        Print(128,"don't display time for moves played in game.\n");
      }
      else if (OptionMatch("changes",args[1])) {
        display_options|=2;
        Print(128,"display PV each time it changes.\n");
      }
      else if (OptionMatch("nochanges",args[1])) {
        display_options&=4095-2;
        Print(128,"don't display PV each time it changes.\n");
      }
      else if (OptionMatch("variation",args[1])) {
        display_options|=4;
        Print(128,"display PV at end of each iteration.\n");
      }
      else if (OptionMatch("novariation",args[1])) {
        display_options&=4095-4;
        Print(128,"don't display PV at end of each iteration.\n");
      }
      else if (OptionMatch("stats",args[1])) {
        display_options|=8;
        Print(128,"display statistics at end of each search.\n");
      }
      else if (OptionMatch("nostats",args[1])) {
        display_options&=4095-8;
        Print(128,"don't.display statistics at end of each search.\n");
      }
      else if (OptionMatch("extstats",args[1])) {
        display_options|=16;
        Print(128,"display extended statistics at end of each search.\n");
      }
      else if (OptionMatch("noextstats",args[1])) {
        display_options&=4095-16;
        Print(128,"don't display extended statistics at end of each search.\n");
      }
      else if (OptionMatch("movenum",args[1])) {
        display_options|=64;
        Print(128,"display move numbers in variations.\n");
      }
      else if (OptionMatch("nomovenum",args[1])) {
        display_options&=4095-64;
        Print(128,"don't display move numbers in variations.\n");
      }
      else if (OptionMatch("moves",args[1])) {
        display_options|=32;
        Print(128,"display ply-1 moves as they are searched.\n");
      }
      else if (OptionMatch("nomoves",args[1])) {
        display_options&=4095-32;
        Print(128,"don't display ply-1 moves as they are searched.\n");
      }
      else if (OptionMatch("general",args[1])) {
        display_options|=128;
        Print(128,"display informational messages.\n");
      }
      else if (OptionMatch("nogeneral",args[1])) {
        display_options&=4095-128;
        Print(128,"don't display informational messages.\n");
      }
      else if (OptionMatch("*",args[1])) {
        if (display_options&1)
          printf("display time for moves\n");
        if (display_options&2)
          printf("display variation when it changes.\n");
        if (display_options&4)
          printf("display variation at end of iteration.\n");
        if (display_options&8)
          printf("display basic search stats.\n");
        if (display_options&16)
          printf("display extended search stats.\n");
        if (display_options&32)
          printf("display ply-1 moves as they are searched.\n");
        if (display_options&64)
          printf("display move numbers in variations.\n");
        if (display_options&128)
          printf("display general messages.\n");
      }
      else break;
      return(1);
    } while(0);
    if (nargs > 1) {
      if (thinking || pondering) return (2);
      tree->position[1]=tree->position[0];
      PreEvaluate(tree,wtm);
      if (OptionMatch("pawn",args[1])) {
        DisplayPieceBoards(pawn_value_w,pawn_value_b);
        i=Evaluate(tree,1,1,-99999,99999);
        printf(" -----------------weak-----------------");
        printf("      -----------------weak-----------------\n");
        for (i=128;i;i=(i>>1)) printf("%4d ",(i&tree->pawn_score.weak_w)!=0);
        printf("    ");
        for (i=128;i;i=(i>>1)) printf("%4d ",(i&tree->pawn_score.weak_b)!=0);
        printf("\n");
      }
      if (OptionMatch("knight",args[1]))
        DisplayPieceBoards(knight_value_w,knight_value_b);
      if (OptionMatch("bishop",args[1]))
        DisplayPieceBoards(bishop_value_w,bishop_value_b);
      if (OptionMatch("rook",args[1]))
        DisplayPieceBoards(rook_value_w,rook_value_b);
      if (OptionMatch("queen",args[1]))
        DisplayPieceBoards(queen_value_w,queen_value_b);
      if (OptionMatch("king",args[1]))
        DisplayPieceBoards(king_value_w,king_value_b);
    }
    else DisplayChessBoard(stdout,display);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "delay" command sets a specific delay (in ms) for      |
|   auto232 synchronization.                               |
|                                                          |
 ----------------------------------------------------------
*/
  else if (!strcmp("delay",*args)) {
    if (nargs < 2) {
      printf("usage:  delay <n>\n");
      return(1);
    }
    auto232_delay=atoi(args[1]);
    Print(4095,"auto232 delay value set to %d ms.\n",auto232_delay);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "depth" command sets a specific search depth to        |
|   control the tree search depth. [xboard compatibility]. |
|                                                          |
 ----------------------------------------------------------
*/
  else if (!strcmp("depth",*args)) {
    if (nargs < 2) {
      printf("usage:  depth <n>\n");
      return(1);
    }
    search_depth=atoi(args[1]);
    Print(4095,"search depth set to %d.\n",search_depth);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "draw" is used to offer Crafty a draw.                 |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("draw",*args)) {
    if (nargs == 1) {
      int drawsc=DrawScore(1);
      if (move_number<40 || !accept_draws) drawsc=-300;
      if (last_search_value<=drawsc && (tc_increment!=0 ||
          tc_time_remaining_opponent>=1000)) {
        if (xboard) Print(4095,"tellics draw\n");
        else Print(4095,"Draw accepted.\n");
        Print(4095,"1/2-1/2 {Draw agreed}\n");
        strcpy(pgn_result,"1/2-1/2");
      }
      else {
        if (xboard) {
          Print(4095,"tellics decline\n");
          Print(4095,"Decline\n");
        }
        else Print(4095,"Draw declined.\n");
      }
    }
    else {
      if (!strcmp(args[1],"accept")) {
        accept_draws=1;
        Print(128,"accept draw offers\n");
      }
      else if (!strcmp(args[1],"decline")) {
        accept_draws=0;
        Print(128,"decline draw offers\n");
      }
      else Print(128,"usage: draw accept|decline\n");
    }
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "drawscore" sets the default draw score (which is      |
|    forced to zero when the endgame is reached.)          |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("drawscore",*args)) {
    if (nargs < 2) {
      printf("usage:  drawscore <n>\n");
      return(1);
    }
    default_draw_score=atoi(args[1]);
    printf("draw score set to %7.2f pawns.\n",
           ((float) default_draw_score) / 100.0);
  }
/*
 ----------------------------------------------------------
|                                                          |
|  "easy" command disables thinking on opponent's time.    |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("easy",*args)) {
    ponder=0;
    Print(4095,"pondering disabled.\n");
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "echo" command displays messages from command file.    |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("echo",*args) || OptionMatch("title",*args)) {
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "edit" command modifies the board position.            |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("edit",*args) && strcmp(*args,"ed")) {
    if (thinking || pondering) return (2);
    Edit();
    move_number=1; /* discard history */
    if (!wtm) {
      wtm=1;
      Pass();
    }
    ponder_move=0;
    last_pv.path_iteration_depth=0;
    last_pv.path_length=0;
    strcpy(buffer,"savepos *");
    (void) Option(tree);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "egtb" command enables/disables tablebases and sets    |
|   the number of pieces available for probing.            |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("egtb",*args)) {
    if (nargs < 2) printf("usage:  tb <n>\n");
    EGTBlimit=atoi(args[1]);
    if (EGTBlimit!=0 && EGTBlimit!=4 && EGTBlimit!=5) {
      Print(4095,"egtb value must be 0, 4 or 5 *only*\n");
      EGTBlimit=0;
    }
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "end" (or "quit") command terminates the program.      |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("end",*args) || OptionMatch("quit",*args)) {
    if (moves_out_of_book)
      LearnBook(tree,crafty_is_white,last_search_value,0,0,1);
    Print(4095,"execution complete.\n");
    fflush(stdout);
    if (book_file) fclose(book_file);
    if (books_file) fclose(books_file);
    if (book_lrn_file) fclose(book_lrn_file);
    if (position_file) fclose(position_file);
    if (position_lrn_file) fclose(position_lrn_file);
    if (history_file) fclose(history_file);
    if (log_file) fclose(log_file);
    EGTerm();
    exit(0);
  }
/*
 ----------------------------------------------------------
|                                                          |
|  "eot" command is a no-operation that is used to keep    |
|  Crafty and the ICS interface in sync.                   |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("eot",*args)) {
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "evtest" command runs a test suite of problems and     |
|   prints evaluations only.                               |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("evtest",*args)) {
    if (thinking || pondering) return(2);
    if (nargs < 2) {
      printf("usage:  evtest <filename> [exitcnt]\n");
      return(1);
    }
    EVTest(args[1]);
    ponder_move=0;
    last_pv.path_iteration_depth=0;
    last_pv.path_length=0;
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "exit" command resets input device to STDIN.           |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("exit",*args)) {
    if (analyze_mode) return(0);
    if (input_stream != stdin) fclose(input_stream);
    input_stream=stdin;
    ReadClear();
    Print(4095,"\n");
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "extension" command allows setting the various search  |
|   extension depths to any reasonable value between 0 and |
|   1.0                                                    |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("ext",*args)) {
    if (nargs < 3) {
      printf("usage:  ext/name=n\n");
      return(1);
    }
    if (OptionMatch("incheck",args[1])) {
      float ext=atof(args[2]);
      incheck_depth=60.0*ext;
      if (incheck_depth < 0) incheck_depth=0;
      if (incheck_depth > 60) incheck_depth=60;
    }
    if (OptionMatch("onerep",args[1])) {
      float ext=atof(args[2]);
      onerep_depth=60.0*ext;
      if (onerep_depth < 0) onerep_depth=0;
      if (onerep_depth > 60) onerep_depth=60;
    }
    if (OptionMatch("pushpp",args[1])) {
      float ext=atof(args[2]);
      pushpp_depth=60.0*ext;
      if (pushpp_depth < 0) pushpp_depth=0;
      if (pushpp_depth > 60) pushpp_depth=60;
    }
    if (OptionMatch("recapture",args[1])) {
      float ext=atof(args[2]);
      recap_depth=60.0*ext;
      if (recap_depth < 0) recap_depth=0;
      if (recap_depth > 60) recap_depth=60;
    }
    if (OptionMatch("singular",args[1])) {
      float ext=atof(args[2]);
      singular_depth=60.0*ext;
      if (singular_depth < 0) singular_depth=0;
      if (singular_depth > 60) singular_depth=60;
    }
    if (OptionMatch("threat",args[1])) {
      float ext=atof(args[2]);
      threat_depth=60.0*ext;
      if (threat_depth < 0) threat_depth=0;
      if (threat_depth > 60) threat_depth=60;
    }
    Print(1,"one-reply extension..................%4.2f\n",(float) onerep_depth/60.0);
    Print(1," in-check extension..................%4.2f\n",(float) incheck_depth/60.0);
    Print(1,"recapture extension..................%4.2f\n",(float) recap_depth/60.0);
    Print(1,"   pushpp extension..................%4.2f\n",(float) pushpp_depth/60.0);
    Print(1,"mate thrt extension..................%4.2f\n",(float) threat_depth/60.0);
    Print(1," singular extension..................%4.2f\n",(float) singular_depth/60.0);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "flag" command controls whether Crafty will call the   |
|   flag in xboard/winboard games (to end the game.)       |
|                                                          |
 ----------------------------------------------------------
*/
  else if (!strcmp("flag",*args)) {
    if (nargs < 2) {
      printf("usage:  flag on|off\n");
      return(1);
    }
    if (!strcmp(args[1],"on")) call_flag=1;
    else if (!strcmp(args[1],"off")) call_flag=0;
   
    if (call_flag) Print(4095,"end game on time forfeits\n");
    else Print(4095,"ignore time forfeits\n");
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "flip" command flips the board, interchanging each     |
|   rank with the corresponding rank on the other half of  |
|   the board, and also reverses the color of all pieces.  |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("flip",*args)) {
    int file, rank, piece;
    if (thinking || pondering) return(2);
    for (rank=0;rank<4;rank++) {
      for (file=0;file<8;file++) {
        piece=-PieceOnSquare((rank<<3)+file);
        PieceOnSquare((rank<<3)+file)=-PieceOnSquare(((7-rank)<<3)+file);
        PieceOnSquare(((7-rank)<<3)+file)=piece;
      }
    }
    SetChessBitBoards(&tree->position[0]);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "flop" command flops the board, interchanging each     |
|   file with the corresponding file on the other half of  |
|   the board.                                             |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("flop",*args)) {
    int file, rank, piece;
    if (thinking || pondering) return(2);
    for (rank=0;rank<8;rank++) {
      for (file=0;file<4;file++) {
        piece=PieceOnSquare((rank<<3)+file);
        PieceOnSquare((rank<<3)+file)=PieceOnSquare((rank<<3)+7-file);
        PieceOnSquare((rank<<3)+7-file)=piece;
      }
    }
    SetChessBitBoards(&tree->position[0]);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "force" command forces the program to make a specific  |
|   move instead of its last chosen move.                  |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("force",*args)) {
    int move, movenum, save_move_number;
    char text[16];

    if (xboard) {
      force=1;
      return(3);
    }
    if (thinking || pondering) return (2);
    if (nargs < 2) {
      printf("usage:  force <move>\n");
      return(1);
    }
    ponder_move=0;
    last_pv.path_iteration_depth=0;
    last_pv.path_length=0;
    save_move_number=move_number;
    movenum=move_number;
    if (wtm) movenum--;
    strcpy(text,args[1]);
    sprintf(buffer,"reset %d",movenum);
    wtm=ChangeSide(wtm);
    (void) Option(tree);
    move=InputMove(tree,text,0,wtm,0,0);
    if (move) {
      if (input_stream != stdin) printf("%s\n",OutputMove(tree,move,0,wtm));
      fseek(history_file,((movenum-1)*2+1-wtm)*10,SEEK_SET);
      fprintf(history_file,"%9s\n",OutputMove(tree,move,0,wtm));
      MakeMoveRoot(tree,move,wtm);
      last_pv.path_iteration_depth=0;
      last_pv.path_length=0;
    }
    else if (input_stream == stdin) printf("illegal move.\n");
    wtm=ChangeSide(wtm);
    move_number=save_move_number;
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "go" command does nothing, except force main() to      |
|   start a search.  ("move" is an alias for go).          |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("go",*args) || OptionMatch("move",*args)) {
    char temp[64];
    if (thinking) return(2);
    if (wtm) {
      if (strncmp(pgn_white,"Crafty",6)) {
        strcpy(temp,pgn_white);
        strcpy(pgn_white,pgn_black);
        strcpy(pgn_black,temp);
      }
    }
    else{
      if (strncmp(pgn_black,"Crafty",6)) {
        strcpy(temp,pgn_white);
        strcpy(pgn_white,pgn_black);
        strcpy(pgn_black,temp);
      }
    }
    return(-1);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "history" command displays game history (moves).       |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("history",*args)) {
    int i;
    char buffer[128];

    printf("    white       black\n");
    for (i=0;i<(move_number-1)*2-wtm+1;i++) {
      fseek(history_file,i*10,SEEK_SET);
      fscanf(history_file,"%s",buffer);
      if (!(i%2)) printf("%3d",i/2+1);
      printf("  %-10s",buffer);
      if (i%2 == 1) printf("\n");
    }
    if (ChangeSide(wtm))printf("  ...\n");
  }
/*
 ----------------------------------------------------------
|                                                          |
|  "hard" command enables thinking on opponent's time.     |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("hard",*args)) {
    ponder=1;
    Print(4095,"pondering enabled.\n");
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "hash" command controls the transposition table size.  |
|   the size can be entered in one of three ways:          |
|                                                          |
|      hash=nnn  where nnn is in bytes.                    |
|      hash=nnnK where nnn is in K bytes.                  |
|      hash=nnnM where nnn is in M bytes.                  |
|                                                          |
|   the only restriction is that the hash table is com-    |
|   puted as follows:  one entry is 16 bytes long.  there  |
|   are 4 tables, two for black, two for white, with one   |
|   of each being twice the size of the other for the same |
|   side.  this means that one entry in one of the small   |
|   tables corresponds to two in the other, so one entry   |
|   really translates to six entries.  Therefore, the size |
|   that is entered is divided by 6*16, and then rounded   |
|   down to the nearest power of two which is a restric-   |
|   tion on the size of a single table.                    |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("hash",*args)) {
    int i, new_hash_size;

    if (thinking || pondering) return(2);
    if (nargs > 1) {
      new_hash_size=atoi(args[1]);
      if (strchr(args[1],'K') || strchr(args[1],'k')) new_hash_size*=1<<10;
      if (strchr(args[1],'M') || strchr(args[1],'m')) new_hash_size*=1<<20;
      if (new_hash_size < 65536) {
        printf("ERROR.  Minimum hash table size is 64K bytes.\n");
        return(1);
      }
      if (new_hash_size > 0) {
        if (hash_table_size) {
          free(trans_ref_wa);
          free(trans_ref_wb);
          free(trans_ref_ba);
          free(trans_ref_bb);
        }
        new_hash_size/=16*6;
        for (log_hash=0;log_hash<(int) (8*sizeof(int));log_hash++)
          if ((1<<(log_hash+1)) > new_hash_size) break;
        if (log_hash) {
          hash_table_size=1<<log_hash;
          trans_ref_wa=malloc(16*hash_table_size);
          trans_ref_wb=malloc(16*2*hash_table_size);
          trans_ref_ba=malloc(16*hash_table_size);
          trans_ref_bb=malloc(16*2*hash_table_size);
          if (!trans_ref_wa || !trans_ref_wb || !trans_ref_ba || !trans_ref_bb) {
            printf("malloc() failed, not enough memory.\n");
            free(trans_ref_wa);
            free(trans_ref_wb);
            free(trans_ref_ba);
            free(trans_ref_bb);
            hash_table_size=0;
            log_hash=0;
            trans_ref_wa=0;
            trans_ref_wb=0;
            trans_ref_ba=0;
            trans_ref_bb=0;
          }
          hash_maska=(1<<log_hash)-1;
          hash_maskb=(1<<(log_hash+1))-1;
          for (i=0;i<hash_table_size;i++) {
            (trans_ref_wa+i)->word1=Shiftl((BITBOARD) 7,61);
            (trans_ref_wa+i)->word2=0;
            (trans_ref_ba+i)->word1=Shiftl((BITBOARD) 7,61);
            (trans_ref_ba+i)->word2=0;
          }
          for (i=0;i<2*hash_table_size;i++) {
            (trans_ref_wb+i)->word1=0;
            (trans_ref_wb+i)->word2=0;
            (trans_ref_bb+i)->word1=0;
            (trans_ref_bb+i)->word2=0;
          }
        }
        else {
          trans_ref_wa=0;
          trans_ref_wb=0;
          trans_ref_ba=0;
          trans_ref_bb=0;
          hash_table_size=0;
          log_hash=0;
        }
      }
      else Print(4095,"ERROR:  hash table size must be > 0\n");
    }
    if (hash_table_size*6*sizeof(HASH_ENTRY) < 1<<20)
      Print(4095,"hash table memory = %dK bytes.\n",
            hash_table_size*6*sizeof(HASH_ENTRY)/(1<<10));
    else {
      if (hash_table_size*6*sizeof(HASH_ENTRY)%(1<<20))
        Print(4095,"hash table memory = %.1fM bytes.\n",
              (float) hash_table_size*6*sizeof(HASH_ENTRY)/(1<<20));
      else
        Print(4095,"hash table memory = %dM bytes.\n",
              hash_table_size*6*sizeof(HASH_ENTRY)/(1<<20));
    }
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "hashp" command controls the pawn hash table size.     |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("hashp",*args)) {
    int i, new_hash_size;

    if (thinking || pondering) return(2);
    if (nargs > 1) {
      new_hash_size=atoi(args[1]);
      if (strchr(args[1],'K') || strchr(args[1],'k')) new_hash_size*=1<<10;
      if (strchr(args[1],'M') || strchr(args[1],'m')) new_hash_size*=1<<20;
      if (new_hash_size > 0) {
        if (pawn_hash_table) {
          free(pawn_hash_table);
          pawn_hash_table_size=0;
          log_pawn_hash=0;
          pawn_hash_table=0;
        }
        new_hash_size/=sizeof(PAWN_HASH_ENTRY);
        for (log_pawn_hash=0;
             log_pawn_hash<(int) (8*sizeof(int));
             log_pawn_hash++)
          if ((1<<(log_pawn_hash+1)) > new_hash_size) break;
        pawn_hash_table_size=1<<log_pawn_hash;
        pawn_hash_table=malloc(sizeof(PAWN_HASH_ENTRY)*pawn_hash_table_size);
        if (!pawn_hash_table) {
          printf("malloc() failed, not enough memory.\n");
          free(pawn_hash_table);
          pawn_hash_table_size=0;
          log_pawn_hash=0;
          pawn_hash_table=0;
        }
        pawn_hash_mask=((unsigned int) 037777777777)>>(32-log_pawn_hash);
        for (i=0;i<pawn_hash_table_size;i++) {
          (pawn_hash_table+i)->key=0;
          (pawn_hash_table+i)->p_score=0;
          (pawn_hash_table+i)->black_protected=0;
          (pawn_hash_table+i)->white_protected=0;
          (pawn_hash_table+i)->black_pof=0;
          (pawn_hash_table+i)->white_pof=0;
          (pawn_hash_table+i)->weak_b=0;
          (pawn_hash_table+i)->weak_w=0;
          (pawn_hash_table+i)->black_defects_k=0;
          (pawn_hash_table+i)->black_defects_q=0;
          (pawn_hash_table+i)->white_defects_k=0;
          (pawn_hash_table+i)->white_defects_q=0;
          (pawn_hash_table+i)->passed_w=0;
          (pawn_hash_table+i)->passed_w=0;
          (pawn_hash_table+i)->outside=0;
        }
      }
      else Print(4095,"ERROR:  pawn hash table size must be > 0\n");
    }
    if (pawn_hash_table_size*sizeof(PAWN_HASH_ENTRY) < 1<<20)
      Print(4095,"pawn hash table memory = %dK bytes.\n",
            pawn_hash_table_size*sizeof(PAWN_HASH_ENTRY)/(1<<10));
    else {
      if (pawn_hash_table_size*sizeof(PAWN_HASH_ENTRY)%(1<<20))
        Print(4095,"pawn hash table memory = %.1fM bytes.\n",
              (float) pawn_hash_table_size*sizeof(PAWN_HASH_ENTRY)/(1<<20));
      else
        Print(4095,"pawn hash table memory = %dM bytes.\n",
              pawn_hash_table_size*sizeof(PAWN_HASH_ENTRY)/(1<<20));
    }
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "help" command lists commands/options.                 |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("help",*args)) {
    if (nargs > 1) {
      if (!strcmp("analyze",args[1])) {
        printf("analyze\n");
        printf("the analyze command puts Crafty into a mode where it will\n");
        printf("search forever in the current position.  when a move is\n");
        printf("entered, crafty will make that move, switch sides, and\n");
        printf("again compute, printing analysis as it searches.  you can\n");
        printf("back up a move by entering \"back\" or you can back up\n");
        printf("several moves by entering \"back <n>\".  note that <n> is\n");
        printf("the number of moves, counting each player's move as one.\n");
      }
      else if (!strcmp("annotate",args[1])) {
        printf("annotate filename b|w|bw moves margin time [n]\n");
        printf("where filename is the input file with game moves, while the\n");
        printf("output will be written to filename.can.  the input file is\n");
        printf("PGN-compatible with one addition, the ability to request that\n");
        printf("alternative moves also be analyzed at any point.  to do this\n");
        printf("at the point where you have alternative moves, simply include\n");
        printf("them in braces {move1, move2}, and Crafty will then search\n");
        printf("them also. b/w/bw indicates whether to annotate only the white\n");
        printf("side (w), the black side (b) or both (bw).  moves indicates\n");
        printf("which moves to annotate.  a single value says start at the\n");
        printf("indicated move and go through the entire game.  a range (20-30)\n");
        printf("annoates the given range only. margin is the difference between\n");
        printf("the search value for the move played in the game, and the best move\n");
        printf("crafty found, before a comment is generated (pawn=1.0).  time is\n");
        printf("the time limit per move in seconds.  if the optional \"n\" is\n");
        printf("appended, this produces N best moves/scores/PV's, rather than\n");
        printf("just the very best move.  it won't display any move that is worse\n");
        printf("than the actual game move played, but you can use -N to force\n");
        printf("Crafty to produce N PV's regardless of how bad they get.\n");
      }
      else if (!strcmp("book",args[1])) {
        printf("you can use the following commands to customize how the\n");
        printf("program uses the opening book(book.bin and books.bin).\n");
        printf("typically, book.bin contains a large opening database made\n");
        printf("from GM games.  books.bin is a short, customized book that\n");
        printf("contains selected lines that are well-suited to Crafty's\n");
        printf("style of play.  the <flags> can further refine how this\n");
        printf("small book file is used to encourage/avoid specific lines.\n");
        printf("book[s] create [<filename>] [maxply] [mp] [wpc]...creates a\n");
        printf("   new book by first removing the old book.bin.  it then\n");
        printf("   will parse <filename> and add the moves to book.bin (if\n");
        printf("   the book create command was used) or to books.bin (if the\n");
        printf("   books create command was used.)  <maxply> truncates book\n");
        printf("   lines after that many plies (typically 60).  <mp> will \n");
        printf("   exclude *any* move not appearing <mp> times in the input.\n");
        printf("   <wpc> is the winning percentage.  50 means exclude any\n");
        printf("   book move that doesn't have at least 50%% as many wins as\n");
        printf("   losses.\n");
        printf("book mask accept <chars>...............sets the accept mask to\n");
        printf("   the flag characters in <chars> (see flags below.)  any flags\n");
        printf("   set in this mask will include either (a) moves with the \n");
        printf("   flag set, or (b) moves with no flags set.\n");
        printf("more...");
        fflush(stdout);
        (void) Read(1,buffer);
        printf("book mask reject <chars>...............sets the reject mask to\n");
        printf("   the flag characters in <chars> (see flags below.)  any flags\n");
        printf("   set in this mask will reject any moves with the flag\n");
        printf("   set (in the opening book.)\n");
        printf("book off...............................turns the book completely off.\n");
        printf("book random 0|1........................disables/enables randomness.\n");
        printf("bookw weight <v>.......................sets weight for book ordering.\n");
        printf("   (weights are freq (frequency), eval (evaluation)\n");
        printf("   and learn (learned scores).\n");
        printf("book width n...........................specifies how many moves from\n");
        printf("   the sorted set of book moves are to be considered.  1 produces\n");
        printf("   the best move from the set, but provides little randomness.\n");
        printf("   99 includes all moves in the book move set.\n");
        printf("more...");
        fflush(stdout);
        (void) Read(1,buffer);
        printf("flags are one (or more) members of the following set of\n");
        printf("characters:  {?? ? = ! !! 0 1 2 3 4 5 6 7 8 9 A B C D E F}\n");
        printf("normally, ?? means never play, ? means rarely play,\n");
        printf("= means drawish opening, ! means good move, !! means always\n");
        printf("play, and 0-F are user flags that a user can add to any\n");
        printf("move in the book, and by setting the right mask (above) can\n");
        printf("force the program to either always play the move or never\n");
        printf("play the move.  the special character * means all flags\n");
        printf("and is probably dangerous to use.\n");
        printf("flags are added to a move by entering the move, a / or \\\n");
        printf("followed by the flags.  / means add the flags to the move\n");
        printf("preserving other flags already there while \\ means replace\n");
        printf("any flags with those following the \\.\n");
        printf("the format of the book text (raw data) is as follows:\n");
        printf("[title information] (required)\n");
        printf("e4 e5 ... (a sequence of moves)\n");
        printf("[title information for next line] (required)\n");
        printf("e4 e6 ...\n");
        printf("end (optional)\n");
        printf("\n");
      }
      else if (!strcmp("display",args[1])) {
        printf("display changes   -> display variation when it changes.\n");
        printf("display extstats  -> display search extension statistics.\n");
        printf("display hashstats -> display search hashing statistics.\n");
        printf("display movenum   -> display move numbers in PV.\n");
        printf("display moves     -> display moves as they are searched.\n");
        printf("display stats     -> display basic search statistics.\n");
        printf("display time      -> display time for moves.\n");
        printf("display variation -> display variation at end of iteration.\n");
      }
      else if (OptionMatch("edit",args[1])) {
        printf("edit is used to set up or modify a board position.  it \n");
        printf("recognizes 4 \"commands\" that it uses to alter/set up the\n");
        printf("board position (with appropriate aliases to interface with\n");
        printf("x\n");
        printf("\n");
        printf("# command causes edit to clear the chess board\n");
        printf("c command causes edit to toggle piece color.\n");
        printf("white command causes edit to place white pieces on the\n");
        printf("board; black command causes edit to place black pieces on\n");
        printf("the \n");
        printf("end (\".\" for xboard) causes edit to exit.\n");
        printf("\n");
        printf("three strings of the form [piece][file][rank] will\n");
        printf("place a [piece] on square [file][rank].  the color is set\n");
        printf("by the previous white/black command.  ex:  Ke8 puts a king\n");
        printf("on square e8\n");
        printf("\n");
      }
      else if (OptionMatch("list",args[1])) {
        printf("list is used to update the GM/IM/computer lists, which are\n");
        printf("used internally to control how crafty uses the opening book.\n");
        printf("Syntax:  list GM|IM|C [+|-name] ...\n");
        printf("   GM/IM/C selects the appropriate list.  if no name is given,\n");
        printf("the list is displayed.  if a name is given, it must be preceeded\n");
        printf("by a + (add to list) or -(remove from list).  note that this\n");
        printf("list is not saved in a file, so that anything added or removed\n");
        printf("will be lost when Crafty is re-started.  To solve this, these\n");
        printf("commands can be added to the .craftyrc file.\n");
      }
      else if (OptionMatch("pgn",args[1])) {
        printf("the pgn command is used to set the various PGN headers\n");
        printf("which are printed at the top of a PGN file produced by the\n");
        printf("savegame command.\n");
        printf("options are Event, Site, Round, White, WhiteElo, Black,\n");
        printf("BlackElo, and Result.  each is followed by the appropriate\n");
        printf("value.  most of these should likely be placed in the\n");
        printf("crafty.rc/.craftyrc file since they will be constant for a\n");
        printf("complete event.\n");
      }
      else if (OptionMatch("setboard",args[1])) {
        printf("sb is used to set up the board in any position desired.  it\n");
        printf("uses a forsythe-like string of characters to describe the\n");
        printf("board position.\n");
        printf("the standard piece codes p,n,b,r,q,k are used to denote the\n");
        printf("piece on a square, upper/lower case is used to indicate the\n");
        printf("color (WHITE/black) of the piece.\n");
        printf("\n");
        printf("the pieces are entered with the ranks on the black side of\n");
        printf("the board entered first, and the ranks on the white side\n");
        printf("entered last (ie rank 8 through rank 1).  empty squares, \n");
        printf("a number between 1 and 8 to indicate how many adjacent\n");
        printf("squares are empty.  use a / to terminate each rank after\n");
        printf("all pieces for that rank have been entered.\n");
        printf("\n");
        printf("more...");
        fflush(stdout);
        (void) Read(1,buffer);
        printf("the following input will setup the board position that\n");
        printf("is given below:\n");
        printf("\n");
        printf("                  K2R/PPP////q/5ppp/7k/ b\n");
        printf("\n");
        printf("this assumes that k represents a white king and -q\n");
        printf("represents a black queen.\n");
        printf("\n");
        printf("                   k  *  *  r  *  *  *  *\n");
        printf("                   p  p  p  *  *  *  *  *\n");
        printf("                   *  *  *  *  *  *  *  *\n");
        printf("                   *  *  *  *  *  *  *  *\n");
        printf("                   *  *  *  *  *  *  *  *\n");
        printf("                  -q  *  *  *  *  *  *  *\n");
        printf("                   *  *  *  *  * -p -p -p\n");
        printf("                   *  *  *  *  *  *  * -k\n");
        printf("\n");
        printf("the character after the final / should be either b or w to\n");
        printf("indicate the side to move.  after this side-to-move field\n");
        printf("any of the following characters can appear to indicate the\n");
        printf("following:  KQ: white can castle kingside/queenside/both;\n");
        printf("kq: same for black;  a1-h8: indicates the square occupied\n");
        printf("by a pawn that can be captured en passant.\n");
      }
      else if (!strcmp("test",args[1])) {
        printf("test <filename> [N]\n");
        printf("test is used to run a suite of \"crafty format\"\n");
        printf("test positions in a batch run.  <filename> is the\n");
        printf("name of the file in crafty test format.  [N] is an\n");
        printf("optional paremeter that is used to shorten the test\n");
        printf("time.  If crafty likes the solution move for [N]\n");
        printf("consecutive iterations, it will stop searching that\n");
        printf("position and consider it correct.  This makes a Win At\n");
        printf("Chess 60 second run take under 1/2 hour, for example.\n");
        printf("the \"crafty format\" requires three lines per position.\n");
        printf("The first line must be a \"title\" line and is used to\n");
        printf("identify each position.  The second line is a \"setboard\"\n");
        printf("command to set the position.  The third line is a line that\n");
        printf("begins with \"solution\", and then is followed by one or\n");
        printf("more solution moves.  If a position is correct only if a\n");
        printf("particular move or moves is *not* played, enter the move\n");
        printf("followed by a \"?\?, as in Nf3?, which means that this\n");
        printf("position will be counted as correct only if Nf3 is not\n");
        printf("played.\n");
      }
      else if (!strcmp("time",args[1])) {
        printf("time controls whether the program uses cpu time or\n");
        printf("wall-clock time for timing.  for tournament play,\n");
        printf("it is safer to use wall-clock timing, for testing it\n");
        printf("may be more consistent to use cpu timing if the\n");
        printf("machine is used for other things concurrently with the\n");
        printf("tests being run.\n");
        printf("\n");
        printf("time is also used to set the basic search timing\n");
        printf("controls.  the general form of the command is as\n");
        printf("follows:\n");
        printf("\n");
        printf("      time nmoves/ntime/[nmoves/ntime]/[increment]\n");
        printf("\n");
        printf("nmoves/ntime represents a traditional first time\n");
        printf("control when nmoves is an integer representing the\n");
        printf("number of moves and ntime is the total time allowed\n");
        printf("for these moves.  the [optional] nmoves/ntime is a\n");
        printf("traditional secondary time control.  increment is a\n");
        printf("feature related to ics play and emulates the fischer\n");
        printf("clock where <increment> is added to the time left\n");
        printf("after each move is made.\n");
        printf("\n");
        printf("as an alternative, nmoves can be \"sd\" which represents\n");
        printf("a sudden death time control of the remainder of the\n");
        printf("game played in ntime.  the optional secondary time\n");
        printf("control can be a sudden-death time control, as in the\n");
        printf("following example:\n");
        printf("\n");
        printf("        time 60/30/sd/30\n");
        printf("\n");
        printf("this sets 60 moves in 30 minutes, then game in 30\n");
        printf("additional minutes.  an increment can be added if\n");
        printf("desired.\n");
      }
      else printf("no help available for that command\n");
    }
    else {
      printf("alarm on|off..............turns audible alarm on/off.\n");
      printf("analyze...................analyze a game in progress\n");
      printf("annotate..................annotate game [help].\n");
      printf("ansi......................toggles reverse video highlighting.\n");
      printf("bench.....................runs performance benchmark.\n");
      printf("book......................controls book [help].\n");
      printf("black.....................sets black to move.\n");
      printf("clock.....................displays chess clock.\n");
      printf("display...................displays chess board\n");
      printf("display <n>...............sets display options [help]\n");
      printf("draw <n>..................sets default draw score.\n");
      printf("echo......................echos output to display.\n");
      printf("edit......................edit board position. [help]\n");
      printf("epdhelp...................info about EPD facility.\n");
      printf("egtb n....................set number of pieces for EGTB probes\n");
      printf("end.......................terminates program.\n");
      printf("exit......................restores STDIN to key\n");
      printf("force <move>..............forces specific move.\n");
      printf("help [command]............displays help.\n");
      printf("hash n....................sets transposition table size\n");
      printf("                          (n bytes, nK bytes or nM bytes)\n");
      printf("hashp n...................sets pawn hash table size\n");
      printf("history...................display game moves.\n");
      printf("import <filename>.........imports learning data (.lrn files).\n");
      printf("info......................displays program settings.\n");
      printf("more...");
      fflush(stdout);
      (void) Read(1,buffer);
      printf("input <filename> [title]..sets STDIN to <filename>.\n");
      printf("                          (and positions to [title] record.)\n");
      printf("kibitz <n>................sets kibitz mode <n> on ICS.\n");
      printf("level <m> <t> <i>.........sets ICS time controls.\n");
      printf("learn <n>.................enables/disables learning.\n");
      printf("list                      update/display GM/IM/computer lists.\n");
      printf("load <file> <title>       load a position from problem file.\n");
      printf("log on|off................turn logging on/off.\n");
      printf("mode normal|tournament....toggles tournament mode.\n");
      printf("move......................initiates search (same as go).\n");
# if defined(SMP)
      printf("mt n......................sets max parallel threads to use.\n");
      printf("mtmin n...................don't thread last n plies.\n");
      printf("mtmax n...................keep threads within n plies.\n");
# endif
      printf("name......................sets opponent's name.\n");
      printf("new.......................initialize and start new game.\n");
      printf("noise n...................no status until n nodes searched.\n");
      printf("operator <minutes>........allocates operator time.\n");
      printf("perf......................times the move generator/make_move.\n");
      printf("perft.....................tests the move generator/make_move.\n");
      printf("pgn option value..........set PGN header information. [help]\n");
      printf("ponder on|off.............toggle pondering off/on.\n");
      printf("ponder move...............ponder \"move\" as predicted move.\n");
      printf("read <filename>...........read moves in [from <filename>].\n");
      printf("reada <filename>..........read moves in [from <filename>].\n");
      printf("                          (appends to current game history.)\n");
      printf("reset n...................reset game to move n.\n");
      printf("resign <m> <n>............set resign threshold to <m> pawns.\n");
      printf("                          <n> = # of moves before resigning.\n");
      printf("more...");
      fflush(stdout);
      (void) Read(1,buffer);
      printf("savegame <filename>.......saves game in PGN format.\n");
      printf("savepos <filename>........saves position in FEN string.\n");
      printf("score.....................print evaluation of position.\n");
      printf("sd n......................sets absolute search depth.\n");
      printf("search <move>.............search specified move only.\n");
      printf("setboard <FEN>............sets board position to FEN position. [help]\n");
      printf("settc.....................set time controls.\n");
      printf("show book.................toggle book statistics.\n");
      printf("st n......................sets absolute search time.\n");
      printf("test <file> [N]...........test a suite of problems. [help]\n");
      printf("time......................time controls. [help]\n");
      printf("trace n...................display search tree below depth n.\n");
      printf("usage <percentage>........adjusts crafty's time usage up or down.\n");
      printf("whisper n.................sets ICS whisper mode n.\n");
      printf("wild n....................sets ICS wild position (7 for now)\n");
      printf("white.....................sets white to move.\n");
      printf("xboard....................sets xboard compatibility mode.\n");
    }
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "hint" displays the expected move based on the last    |
|   search done. [xboard compatibility]                    |
|                                                          |
 ----------------------------------------------------------
*/
  else if (!strcmp("hint",*args)) {
    if (strlen(hint)) {
      printf("Hint: %s\n",hint);
      fflush(stdout);
    }
  }
/*
 ----------------------------------------------------------
|                                                          |
|  "ics" command is normally invoked from main() via the   |
|  ics command-line option.  it sets proper defaults for   |
|  defaults for the custom crafty/ics interface program.   |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("ics",*args)) {
    ics=1;
    display_options&=4095-32;
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "import" <filename> command is used to import a .lrn   |
|   file (either book.lrn or position.lrn) and store the   |
|   results in crafty's binary files (book.bin or          |
|   position.bin) just as though it had learned those      |
|   results by itself.                                     |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("import",*args)) {
    if (thinking || pondering) return(2);
    nargs=ReadParse(buffer,args," 	;=");
    if (nargs < 2) printf("usage:  import <filename> [clear]\n");
    else LearnImport(tree,nargs-1,args+1);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "input" command directs the program to read input from |
|   a file until eof is reached or an "exit" command is    |
|   encountered while reading the file.                    |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("input",*args)) {
    if (thinking || pondering) return(2);
    nargs=ReadParse(buffer,args," 	=");
    if (nargs < 2) {
      printf("usage:  input <filename>\n");
      return(1);
    }
    if (!(input_stream=fopen(args[1],"r"))) {
      printf("file does not exist.\n");
      input_stream=stdin;
    }
  }
/*
 ----------------------------------------------------------
|                                                          |
|  "info" command gives some information about Crafty.     |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("info",*args)) {
    Print(4095,"Crafty version %s\n",version);
    if (hash_table_size*6*sizeof(HASH_ENTRY) < 1<<20)
      Print(4095,"hash table memory = %dK bytes.\n",
            hash_table_size*6*sizeof(HASH_ENTRY)/(1<<10));
    else {
      if (hash_table_size*6*sizeof(HASH_ENTRY)%(1<<20))
        Print(4095,"hash table memory = %.1fM bytes.\n",
              (float) hash_table_size*6*sizeof(HASH_ENTRY)/(1<<20));
      else
        Print(4095,"hash table memory = %dM bytes.\n",
              hash_table_size*6*sizeof(HASH_ENTRY)/(1<<20));
    }
    if (pawn_hash_table_size*sizeof(PAWN_HASH_ENTRY) < 1<<20)
      Print(4095,"pawn hash table memory = %dK bytes.\n",
            pawn_hash_table_size*sizeof(PAWN_HASH_ENTRY)/(1<<10));
    else {
      if (pawn_hash_table_size*6*sizeof(PAWN_HASH_ENTRY)%(1<<20))
        Print(4095,"pawn hash table memory = %.1fM bytes.\n",
              (float) pawn_hash_table_size*sizeof(PAWN_HASH_ENTRY)/(1<<20));
      else
        Print(4095,"hash table memory = %dM bytes.\n",
              pawn_hash_table_size*sizeof(PAWN_HASH_ENTRY)/(1<<20));
    }
    if (!tc_sudden_death) {
      Print(4095,"%d moves/%d minutes %d seconds primary time control\n",
            tc_moves, tc_time/6000, (tc_time/100)%60);
      Print(4095,"%d moves/%d minutes %d seconds secondary time control\n",
            tc_secondary_moves, tc_secondary_time/6000,
            (tc_secondary_time/100)%60);
      if (tc_increment) Print(4095,"increment %d seconds.\n",tc_increment/100);
    }
    else if (tc_sudden_death == 1) {
      Print(4095," game/%d minutes primary time control\n", tc_time/100);
      if (tc_increment) Print(4095,"increment %d seconds.\n",(tc_increment/100)%60);
    }
    else if (tc_sudden_death == 2) {
      Print(4095,"%d moves/%d minutes primary time control\n",
            tc_moves, tc_time/6000);
      Print(4095,"game/%d minutes secondary time control\n",
            tc_secondary_time/6000);
      if (tc_increment) Print(4095,"increment %d seconds.\n",tc_increment/100);
    }
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "kibitz" command sets kibitz mode for ICS.  =1 will    |
|   kibitz mate announcements, =2 will kibitz scores and   |
|   other info, =3 will kibitz scores and PV, =4 adds the  |
|   list of book moves, =5 displays the PV after each      |
|   iteration completes, and =6 displays the PV each time  |
|   it changes in an iteration.                            |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("kibitz",*args)) {
    if (nargs < 2) {
      printf("usage:  kibitz <level>\n");
      return(1);
    }
    kibitz=atoi(args[1]);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "learn" command enables/disables the learning          |
|   algorithms used in crafty.  these are controlled by    |
|   a single variable with multiple boolean switches in    |
|   it as defined below:                                   |
|                                                          |
|   000 -> no learning enabled.                            |
|   001 -> learn which book moves are good and bad.        |
|   010 -> learn middlegame positions.                     |
|   100 -> learn from game "results" (win/lose).           |
|                                                          |
|   these are entered as an integer, which is formed by    |
|   adding the integer values 1,2,4 to enable the various  |
|   forms of learning.                                     |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("learn",*args)) {
    if (nargs == 2) learning=atoi(args[1]);
    if (learning&book_learning)
      Print(4095,"book learning enabled\n");
    else
      Print(4095,"book learning disabled\n");
    if (learning&result_learning)
      Print(4095,"result learning enabled\n");
    else
      Print(4095,"result learning disabled\n");
    if (learning&position_learning)
      Print(4095,"position learning enabled\n");
    else
      Print(4095,"position learning disabled\n");
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "level" command sets time controls [ics/xboard         |
|   compatibility.]                                        |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("level",*args)) {
    if (nargs < 4) {
      printf("usage:  level <nmoves> <stime> <inc>\n");
      return(1);
    }
    tc_moves=atoi(args[1]);
    tc_time=atoi(args[2])*100;
    tc_increment=atoi(args[3])*100;
    tc_time_remaining=tc_time;
    tc_time_remaining_opponent=tc_time;
    if (!tc_moves) {
      tc_sudden_death=1;
      tc_moves=1000;
      tc_moves_remaining=1000;
    }
    else tc_sudden_death=0;
    if (tc_moves) {
      tc_secondary_moves=tc_moves;
      tc_secondary_time=tc_time;
      tc_moves_remaining=tc_moves;
    }
    if (!tc_sudden_death) {
      Print(4095,"%d moves/%d minutes primary time control\n",
            tc_moves, tc_time/100);
      Print(4095,"%d moves/%d minutes secondary time control\n",
            tc_secondary_moves, tc_secondary_time/100);
      if (tc_increment) Print(4095,"increment %d seconds.\n",tc_increment/100);
    }
    else if (tc_sudden_death == 1) {
      Print(4095," game/%d minutes primary time control\n",tc_time/100);
      if (tc_increment) Print(4095,"increment %d seconds.\n",tc_increment/100);
    }
    tc_time*=60;
    tc_time_remaining=tc_time;
    tc_secondary_time*=60;
    if (tc_time > 30000 || tc_increment > 300) whisper=0;
    if (tc_time <= 6000 && tc_increment <= 100) whisper=0;
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "list" command allows the operator to add or remove    |
|   names from the GM_list, IM_list , computer_list,       |
|   auto_kibitz_list or special_list.                      |
|   The  syntax is "list <list> <option> <name>.           |
|   <list> is one of GM, IM, C, AK or S.                   |
|   The final parameter is a name to add  or remove.       |
|   if the name is in the list, it is removed,             |
|   otherwise it is added.  if no name is given, the list  |
|   is displayed.                                          |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("list",*args)) {
    int i, j;
    char listname[8];
    char **targs;

    targs=args;
    strcpy(listname,args[1]);
    nargs-=2;
    targs+=2;
    
    if (nargs) {
      if (!strcmp(listname,"GM")) {
        if (targs[0][0] == '-') {
          for (i=0;i<number_of_GMs;i++)
            if (!strcmp(GM_list[i],targs[0]+1)) {
              for (j=i;j<number_of_GMs;j++)
                strcpy(GM_list[j],GM_list[j+1]);
              number_of_GMs--;
              i=0;
              Print(4095,"%s removed from GM list.\n",targs[0]+1);
              break;
            }
        }
        else if (targs[0][0] == '+') {
          for (i=0;i<number_of_GMs;i++)
            if (!strcmp(GM_list[i],targs[0]+1)) {
              Print(4095, "Warning: %s is already in GM list.\n",targs[0]+1);
              break;
            }
          if (number_of_GMs >= 512)
            Print(4095,"ERROR!  GM list is full at 512 entries\n");
          else if (i==number_of_GMs) {
            strcpy(GM_list[number_of_GMs++],targs[0]+1);
            Print(4095,"%s added to GM list.\n",targs[0]+1);
          }
        }
        else if (!strcmp(targs[0],"clear")) {
          number_of_GMs=0;
        }
        else printf("error, name must be preceeded by +/- flag.\n");
      }
      if (!strcmp(listname,"S")) {
        if (targs[0][0] == '-') {
          for (i=0;i<number_of_specials;i++)
            if (!strcmp(special_list[i],targs[0]+1)) {
              for (j=i;j<number_of_specials;j++)
                strcpy(special_list[j],special_list[j+1]);
              number_of_specials--;
              i=0;
              Print(4095,"%s removed from special list.\n",targs[0]+1);
 
              break;
            }
        }
        else if (targs[0][0] == '+') {
          for (i=0;i<number_of_specials;i++)
            if (!strcmp(special_list[i],targs[0]+1)) {
              Print(4095, "Warning: %s is already in S list.\n",targs[0]+1);
              break;
            }
          if (number_of_specials >= 512)
            Print(4095,"ERROR!  special list is full at 512 entries\n");
          else if (i==number_of_specials) {
            strcpy(special_list[number_of_specials++],targs[0]+1);
            Print(4095,"%s added to special list.\n",targs[0]+1);
          }
        }         
        else if (!strcmp(targs[0],"clear")) {
          number_of_specials=0;
        }
        else Print(4095,"error, name must be preceeded by +/- flag.\n");
      }
      if (!strcmp(listname,"IM")) {
        if (targs[0][0] == '-') {
          for (i=0;i<number_of_IMs;i++)
            if (!strcmp(IM_list[i],targs[0]+1)) {
              for (j=i;j<number_of_IMs;j++)
                strcpy(IM_list[j],IM_list[j+1]);
              number_of_IMs--;
              i=0;
              Print(4095,"%s removed from IM list.\n",targs[0]+1);
 
              break;
            }
        }
        else if (targs[0][0] == '+') {
          for (i=0;i<number_of_IMs;i++)
            if (!strcmp(IM_list[i],targs[0]+1)) {
              Print(4095, "Warning: %s is already in IM list.\n",targs[0]+1);
              break;
            }
          if (number_of_IMs >= 512)
            Print(4095,"ERROR!  IM list is full at 512 entries\n");
          else if (i==number_of_IMs) {
            strcpy(IM_list[number_of_IMs++],targs[0]+1);
            Print(4095,"%s added to IM list.\n",targs[0]+1);
          }
        }         
        else if (!strcmp(targs[0],"clear")) {
          number_of_IMs=0;
        }
        else Print(4095,"error, name must be preceeded by +/- flag.\n");
      }
      if (!strcmp(listname,"C")) {
        if (targs[0][0] == '-') {
          for (i=0;i<number_of_computers;i++)
            if (!strcmp(computer_list[i],targs[0]+1)) {
              for (j=i;j<number_of_computers;j++)
                strcpy(computer_list[j],computer_list[j+1]);
              number_of_computers--;
              i=0;
              Print(4095,"%s removed from computer list.\n",targs[0]+1);
              break;
            }
        }
        else if (targs[0][0] == '+') {
          for (i=0;i<number_of_computers;i++)
            if (!strcmp(computer_list[i],targs[0]+1)) {
              Print(4095, "Warning: %s is already in C list.\n",targs[0]+1);
              break;
            }
          if (number_of_computers >= 512)
            Print(4095,"ERROR!  C list is full at 512 entries\n");
          else if (i==number_of_computers) {
            strcpy(computer_list[number_of_computers++],targs[0]+1);
            Print(4095,"%s added to computer list.\n",targs[0]+1);
          }
        }
        else if (!strcmp(targs[0],"clear")) {
          number_of_computers=0;
        }
        else Print(4095,"error, name must be preceeded by +/- flag.\n");
      }
      
      if (!strcmp(listname,"AK")) {
        if (targs[0][0] == '-') {
          for (i=0;i<number_auto_kibitzers;i++)
            if (!strcmp(auto_kibitz_list[i],targs[0]+1)) {
              for (j=i;j<number_auto_kibitzers;j++)
                strcpy(auto_kibitz_list[j],auto_kibitz_list[j+1]);
              number_auto_kibitzers--;
              i=0;
              Print(4095,"%s removed from auto kibitz list.\n",targs[0]+1);
              break;
            }
        }
        else if (targs[0][0] == '+') {
          for (i=0;i<number_auto_kibitzers;i++)
            if (!strcmp(auto_kibitz_list[i],targs[0]+1)) {
              Print(4095, "Warning: %s is already in AK list.\n",targs[0]+1);
              break;
            }
          if (number_auto_kibitzers >= 64)
            Print(4095,"ERROR!  AK list is full at 64 entries\n");
          else if (i==number_auto_kibitzers) {
            strcpy(auto_kibitz_list[number_auto_kibitzers++],targs[0]+1);
            Print(4095,"%s added to auto kibitz list.\n",targs[0]+1);
          }
        }
        else if (!strcmp(targs[0],"clear")) {
          number_auto_kibitzers=0;
        }
        else Print(4095,"error, name must be preceeded by +/- flag.\n");
      }
    }
    else {
      if (!strcmp(listname,"GM")) {
        Print(4095,"GM List:\n");
        for (i=0;i<number_of_GMs;i++)
          Print(4095,"%s\n",GM_list[i]);
      }
      else if (!strcmp(listname,"S")) {
        Print(4095,"special List:\n");
        for (i=0;i<number_of_specials;i++)
          Print(4095,"%s\n",special_list[i]);
      }
      else if (!strcmp(listname,"IM")) {
        Print(4095,"IM List:\n");
        for (i=0;i<number_of_IMs;i++)
          Print(4095,"%s\n",IM_list[i]);
      }
      else if (!strcmp(listname,"C")) {
        Print(4095, "computer list:\n");
        for (i=0;i<number_of_computers;i++)
          Print(4095,"%s\n",computer_list[i]);
      }
      else if (!strcmp(listname,"AK")) {
        Print(4095, "auto kibitz list:\n");
        for (i=0;i<number_auto_kibitzers;i++)
          Print(4095,"%s\n",auto_kibitz_list[i]);
      }
    }
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "load" command directs the program to read input from  |
|   a file until a "setboard" command is found  this       |
|   command is then executed, setting up the position for  |
|   a search.                                              |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("load",*args)) {
    char title[64];
    char *readstat;
    FILE *prob_file;

    if (thinking || pondering) return(2);
    nargs=ReadParse(buffer,args," 	=");
    if (nargs < 3) {
      printf("usage:  input <filename> title\n");
      return(1);
    }
    if (!(prob_file=fopen(args[1],"r"))) {
      printf("file does not exist.\n");
      return(1);
    }
    strcpy(title,args[2]);
    while (!feof(prob_file)) {
      readstat=fgets(buffer,128,prob_file);
      if (readstat) {
        char *delim;
        delim=strchr(buffer,'\n');
        if (delim) *delim=0;
        delim=strchr(buffer,'\r');
        if (delim) *delim=' ';
      }
      if (readstat == NULL) break;
      nargs=ReadParse(buffer,args," 	;\n");
      if (!strcmp(args[0],"title") && strstr(buffer,title)) break;
    }
    while (!feof(prob_file)) {
      readstat=fgets(buffer,128,prob_file);
      if (readstat) {
        char *delim;
        delim=strchr(buffer,'\n');
        if (delim) *delim=0;
        delim=strchr(buffer,'\r');
        if (delim) *delim=' ';
      }
      if (readstat == NULL) break;
      nargs=ReadParse(buffer,args," 	;\n");
      if (!strcmp(args[0],"setboard")) {
        Option(tree);
        break;
      }
    }
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "log" command turns log on/off, and also lets you view |
|   the end of the log or copy it to disk as needed.  To   |
|   view the end, simply type "log <n>" where n is the #   |
|   of lines you'd like to see (the last <n> lines).  you  |
|   can add a filename to the end and the output will go   |
|   to this file instead.                                  |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("log",*args)) {
    FILE *output_file;
    char filename[64], buffer[128];

    if (nargs < 2) {
      printf("usage:  log on|off|n [filename]\n");
      return(1);
    }
    if (!strcmp(args[1],"on")) {
      for (log_id=1;log_id <300;log_id++) {
#if defined(MACOS)
        sprintf(log_filename,":%s:log.%03d",log_path,log_id);
        sprintf(history_filename,":%s:game.%03d",log_path,log_id);
#else
        sprintf(log_filename,"%s/log.%03d",log_path,log_id);
        sprintf(history_filename,"%s/game.%03d",log_path,log_id);
#endif
        log_file=fopen(log_filename,"r");
        if (!log_file) break;
        fclose(log_file);
      }
      log_file=fopen(log_filename,"w");
      history_file=fopen(history_filename,"w+");
    }
    else if (!strcmp(args[1],"off")) {
      if (log_file) fclose(log_file);
      log_file=0;
#if defined(MACOS)
      sprintf(filename,":%s:log.%03d",log_path,log_id);
#else
      sprintf(filename,"%s/log.%03d",log_path,log_id);
#endif
      remove(filename);
    }
    else {
      int nrecs, trecs, lrecs;
      char *eof;
      FILE *log;

      nrecs=atoi(args[1]);
      output_file=stdout;
      if (nargs > 2) output_file=fopen(args[2],"w");
      log=fopen(log_filename,"r");
      for (trecs=1; trecs<99999999; trecs++) {
        eof=fgets(buffer,128,log);
        if (eof) {
          char *delim;
          delim=strchr(buffer,'\n');
          if (delim) *delim=0;
          delim=strchr(buffer,'\r');
          if (delim) *delim=' ';
        }
        else break;
      }
      fseek(log,0,SEEK_SET);
      for (lrecs=1; lrecs<trecs-nrecs; lrecs++) {
        eof=fgets(buffer,128,log);
        if (eof) {
          char *delim;
          delim=strchr(buffer,'\n');
          if (delim) *delim=0;
          delim=strchr(buffer,'\r');
          if (delim) *delim=' ';
        }
        else break;
      }
      for (;lrecs<trecs; lrecs++) {
        eof=fgets(buffer,128,log);
        if (eof) {
          char *delim;
          delim=strchr(buffer,'\n');
          if (delim) *delim=0;
          delim=strchr(buffer,'\r');
          if (delim) *delim=' ';
        }
        else break;
        fprintf(output_file,"%s\n",buffer);
      }
      if (output_file != stdout) fclose(output_file);
    }
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "mt" command is used to set the maximum number of      |
|   parallel threads to use, assuming that Crafty was      |
|   compiled with -DSMP.  this value can not be set        |
|   larger than the compiled-in -DCPUS=n value.            |
|                                                          |
 ----------------------------------------------------------
*/
#if defined(SMP)
  else if (OptionMatch("mt",*args)) {
    int proc;
    if (nargs < 2) {
      printf("usage:  mt=<threads>\n");
      return(1);
    }
    if (thinking || pondering) return(3);
    max_threads=atoi(args[1]);
    if (max_threads > CPUS) {
      Print(4095,"ERROR - Crafty was compiled with CPUS=%d.",CPUS);
      Print(4095,"  mt can not exceed this value.\n");
      max_threads=CPUS;
    }
    if (max_threads)
      Print(4095,"max threads set to %d\n",max_threads);
    else
      Print(4095,"parallel threads disabled.\n");
    for (proc=0;proc<CPUS;proc++)
      if (proc >= max_threads) thread[proc]=(TREE*)-1;
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "mtmin" command is used to set the minimum depth of    |
|   a tree before a thread can be started.  this is used   |
|   to prevent the thread creation overhead from becoming  |
|   larger than the time actually needed to search the     |
|   tree.                                                  |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("mtmin",*args)) {
    if (nargs < 2) {
      printf("usage:  mtmin <plies>\n");
      return(1);
    }
    min_thread_depth=INCREMENT_PLY*atoi(args[1]);
    Print(4095,"minimum thread depth set to %d\n",min_thread_depth);
  }
#endif
/*
 ----------------------------------------------------------
|                                                          |
|   "mn" command is used to set the move number to a       |
|   specific value...                                      |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("mn",*args)) {
    if (nargs < 2) {
      printf("usage:  mn <move_number>\n");
      return(1);
    }
    move_number=atoi(args[1]);
    Print(4095,"move number set to %d\n",move_number);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "mode" command sets tournament mode or normal mode.    |
|   tournament mode is used when crafty is in a "real"     |
|   tournament.  it forces draw_score to 0, and makes      |
|   crafty display the chess clock after each move.        |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("mode",*args)) {
    if (nargs > 1) {
      if (!strcmp(args[1],"tournament")) {
        mode=tournament_mode;
        draw_score_normal=1;
        printf("use 'settc' command if a game is restarted after crafty\n");
        printf("has been terminated for any reason.\n");
      }
      else if (!strcmp(args[1],"normal")) {
        mode=normal_mode;
      }
      else {
        printf("usage:  mode normal|tournament\n");
        mode=normal_mode;
      }
    }
    if (mode == tournament_mode) printf("tournament mode.\n");
    else if (mode == normal_mode) printf("normal mode.\n");
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "name" command saves opponents name and writes it into |
|   logfile along with the date/time.  it also scans the   |
|   list of known computers and adjusts its opening book   |
|   to play less "risky" if it matches.  if the opponent   |
|   is in the GM list, it tunes the resignation controls   |
|   to resign earlier.  ditto for IM, although the resign  |
|   threshold is not tightened so much.                    |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("name",*args)) {
    int i;
    char *next;

    if (nargs < 2) {
      printf("usage:  name <name>\n");
      return(1);
    }
    if (wtm) {
      strcpy(pgn_white,args[1]);
      sprintf(pgn_black,"Crafty %s",version);
    }
    else {
      strcpy(pgn_black,args[1]);
      sprintf(pgn_white,"Crafty %s",version);
    }
    Print(4095,"Crafty %s vs %s\n",version,args[1]);
    next=args[1];
    while (*next) {
      *next=tolower(*next);
      next++;
    }
    if (mode != tournament_mode) {
      for (i=0;i<number_auto_kibitzers;i++)
        if (!strcmp(auto_kibitz_list[i],args[1])) {
          kibitz=4;
          auto_kibitzing=1;
          break;
        }
      for (i=0;i<number_of_computers;i++)
        if (!strcmp(computer_list[i],args[1])) {
          Print(128,"playing a computer!\n");
          computer_opponent=1;
          draw_score_normal=1;
          book_selection_width=2;
          usage_level=0;
          book_weight_freq=1.0;
          book_weight_eval=.1;
          book_weight_learn=.2;
          break;
        }
      for (i=0;i<number_of_GMs;i++)
        if (!strcmp(GM_list[i],args[1])) {
          Print(128,"playing a GM!\n");
          book_selection_width=3;
          resign=Min(6,resign);
          resign_count=4;;
          draw_count=8;
          accept_draws=1;
          kibitz=0;
          break;
        }
      for (i=0;i<number_of_specials;i++)
        if (!strcmp(special_list[i],args[1])) {
          Print(128,"playing a special player!\n");
          book_selection_width=4;
          resign=Min(9,resign);
          resign_count=5;
          draw_count=8;
          kibitz=0;
          no_tricks=0;
          break;
        }
      for (i=0;i<number_of_IMs;i++)
        if (!strcmp(IM_list[i],args[1])) {
          Print(128,"playing an IM!\n");
          book_selection_width=4;
          resign=Min(9,resign);
          resign_count=5;
          draw_count=8;
          accept_draws=1;
          kibitz=0;
          break;
        }
      }
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "new" command initializes for a new game.  note that   |
|   "AN" is an alias for this command, for auto232         |
|   compatibility.                                         |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("new",*args) || OptionMatch("AN",*args)) {
    new_game=1;
    if (thinking || pondering) return(3);
    NewGame(0);
    return(3);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "noise" command sets a minimum limit on nodes searched |
|   such that until this number of nodes has been searched |
|   no program output will occur.  this is used to prevent |
|   simple endgames from swamping the display device since |
|   30+ ply searches are possible, which can produce 100's |
|   of lines of output.                                    |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("noise",*args)) {
    if (nargs < 2) {
      printf("usage:  noise <n>\n");
      return(1);
    }
    noise_level=atoi(args[1]);
    Print(4095,"noise level set to %d.\n",noise_level);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "operator" command sets the operator time.  this time  |
|   is the time per move that the operator needs.  it is   |
|   multiplied by the number of moves left to time control |
|   to reserve operator time.                              |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("operator",*args)) {
    if (nargs < 2) {
      printf("usage:  operator <seconds>\n");
      return(1);
    }
    tc_operator_time=ParseTime(args[1])*100;
    Print(4095,"reserving %d seconds per move for operator overhead.\n",
          tc_operator_time/100);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "otime" command sets the opponent's time remaining.    |
|   this is used to determine if the opponent is in time   |
|   trouble, and is factored into the draw score if he is. |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("otime",*args)) {
    if (nargs < 2) {
      printf("usage:  otime <time(unit=.01 secs))>\n");
      return(1);
    }
    tc_time_remaining_opponent=atoi(args[1]);
    if (log_file && time_limit>99)
      fprintf(log_file,"time remaining: %s (opponent).\n",
              DisplayTime(tc_time_remaining_opponent));
    if (call_flag && xboard && tc_time_remaining_opponent <= 1) {
      if (crafty_is_white) Print(4095,"1-0 {Black ran out of time}\n");
      else Print(4095,"0-1 {White ran out of time}\n");
    }
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "output" command sets long or short algebraic output.  |
|   long is Ng1f3, while short is simply Nf3.              |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("output",*args)) {
    if (nargs < 2) {
      printf("usage:  output long|short\n");
      return(1);
    }
    if (!strcmp(args[1],"long")) output_format=1;
    else if (!strcmp(args[1],"short")) output_format=0;
    else printf("usage:  output long|short\n");
    if (output_format == 1)
      Print(4095,"output moves in long algebraic format\n");
    else if (output_format == 0)
      Print(4095,"output moves in short algebraic format\n");
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "bookpath", "logpath" and "tbpath" commands set the    |
|   default paths to find or create these files.           |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("logpath",*args) ||
           OptionMatch("bookpath",*args) ||
           OptionMatch("tbpath",*args)) {
    if (log_file)
      Print(4095,"ERROR -- this must be used on command line only\n");
    else {
      nargs=ReadParse(buffer,args," 	=");
      if (nargs < 2) {
        printf("usage:  bookpath|logpath|tbpath <path>\n");
        return(1);
      }
      if (strstr(args[0],"bookpath")) strcpy(book_path,args[1]);
      else if (strstr(args[0],"logpath")) strcpy(log_path,args[1]);
      else if (strstr(args[0],"tbpath")) strcpy(tb_path,args[1]);
    }
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "perf" command turns times move generator/make_move.   |
|                                                          |
 ----------------------------------------------------------
*/
#define PERF_CYCLES 100000
  else if (OptionMatch("perf",*args)) {
    int i, *mv, clock_before, clock_after;
    float time_used;

    if (thinking || pondering) return(2);
    clock_before = clock();
    while (clock() == clock_before);
    clock_before = clock();
    for (i=0;i<PERF_CYCLES;i++) {
      tree->last[1]=GenerateCaptures(tree, 0, wtm, tree->last[0]);
      tree->last[1]=GenerateNonCaptures(tree, 0, wtm, tree->last[1]);
    }
    clock_after=clock();
    time_used=((float) clock_after-(float) clock_before) / 
              (float) CLOCKS_PER_SEC;
    printf("generated %d moves, time=%.2f seconds\n",
           (tree->last[1]-tree->last[0])*PERF_CYCLES,time_used);
    printf("generated %d moves per second\n",(int) (((float) (PERF_CYCLES*
           (tree->last[1]-tree->last[0])))/time_used));
    clock_before=clock();
    while (clock() == clock_before);
    clock_before = clock();
    for (i=0;i<PERF_CYCLES;i++) {
      tree->last[1]=GenerateCaptures(tree, 0, wtm, tree->last[0]);
      tree->last[1]=GenerateNonCaptures(tree, 0, wtm, tree->last[1]);
      for (mv=tree->last[0];mv<tree->last[1];mv++) {
        MakeMove(tree,0,*mv,wtm);
        UnMakeMove(tree,0,*mv,wtm);
      }
    }
    clock_after=clock();
    time_used=((float) clock_after-(float) clock_before) / 
              (float) CLOCKS_PER_SEC;
    printf("generated/made/unmade %d moves, time=%.2f seconds\n",
      (tree->last[1]-tree->last[0])*PERF_CYCLES, time_used);
    printf("generated/made/unmade %d moves per second\n",(int) (((float) (PERF_CYCLES*
           (tree->last[1]-tree->last[0])))/time_used));
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "perft" command turns tests move generator/make_move.  |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("perft",*args)) {
    int i;

    if (thinking || pondering) return(2);
    if (nargs < 2) {
      printf("usage:  perftest <depth>\n");
      return(1);
    }
    tree->position[1]=tree->position[0];
    tree->last[0]=tree->move_list;
    i=atoi(args[1]);
    total_moves=0;
    OptionPerft(tree,1,i,wtm);
    printf("total moves=%d\n",total_moves);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "pgn" command sets the various PGN header files.       |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("pgn",*args)) {
    int i;

    if (nargs < 3) {
      printf("usage:  pgn <tag> <value>\n");
      return(1);
    }
    if (!strcmp(args[1],"Event")) {
      pgn_event[0]=0;
      for (i=2;i<nargs;i++) {
        strcpy(pgn_event+strlen(pgn_event),args[i]);
        strcpy(pgn_event+strlen(pgn_event)," ");
      }
    }
    else if (!strcmp(args[1],"Site")) {
      pgn_site[0]=0;
      for (i=2;i<nargs;i++) {
        strcpy(pgn_site+strlen(pgn_site),args[i]);
        strcpy(pgn_site+strlen(pgn_site)," ");
      }
    }
    else if (!strcmp(args[1],"Round")) {
      pgn_round[0]=0;
      strcpy(pgn_round,args[2]);
    }
    else if (!strcmp(args[1],"White")) {
      pgn_white[0]=0;
      for (i=2;i<nargs;i++) {
        strcpy(pgn_white+strlen(pgn_white),args[i]);
        strcpy(pgn_white+strlen(pgn_white)," ");
      }
    }
    else if (!strcmp(args[1],"WhiteElo")) {
      pgn_white_elo[0]=0;
      strcpy(pgn_white_elo,args[2]);
    }
    else if (!strcmp(args[1],"Black")) {
      pgn_black[0]=0;
      for (i=2;i<nargs;i++) {
        strcpy(pgn_black+strlen(pgn_black),args[i]);
        strcpy(pgn_black+strlen(pgn_black)," ");
      }
    }
    else if (!strcmp(args[1],"BlackElo")) {
      pgn_black_elo[0]=0;
      strcpy(pgn_black_elo,args[2]);
    }
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "ponder" command toggles pondering off/on or sets a    |
|   move to ponder.                                        |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("ponder",*args)) {
    if (thinking || pondering) return(2);
    if (nargs < 2) {
      printf("usage:  ponder off|on|<move>\n");
      return(1);
    }
    if (!strcmp(args[1],"on")) {
      ponder=1;
      Print(4095,"pondering enabled.\n");
    }
    else if (!strcmp(args[1],"off")) {
      ponder=0;
      Print(4095,"pondering disabled.\n");
    }
    else {
      ponder_move=InputMove(tree,args[1],0,wtm,0,0);
    }
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "post/nopost" command sets/resets "show thinking" mode |
|   for xboard compatibility.                              |
|                                                          |
 ----------------------------------------------------------
*/
  else if (!strcmp("post",*args)) {
    post=1;
  }
  else if (!strcmp("nopost",*args)) {
    post=0;
  }
/*
 ----------------------------------------------------------
|                                                          |
|  "random" command is ignored. [xboard compatibility]     |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("random",*args)) {
    return(xboard);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "rating" is used by xboard to set crafty's rating and  |
|   the opponent's rating, which is used by the learning   |
|   functions.                                             |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("rating",*args)) {
    if (nargs < 3) {
      printf("usage:  rating <crafty> <opponent>\n");
      return(1);
    }
    crafty_rating=atoi(args[1]);
    opponent_rating=atoi(args[2]);
    if (opponent_rating-crafty_rating > 0) default_draw_score=20;
    if (log_file) {
      fprintf(log_file,"Crafty's rating: %d.\n",crafty_rating);
      fprintf(log_file,"opponent's rating: %d.\n",opponent_rating);
    }
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "remove" command backs up the game one whole move,     |
|   leaving the opponent still on move.  it's intended for |
|   xboard compatibility, but works in any mode.           |
|                                                          |
 ----------------------------------------------------------
*/
  else if (!strcmp("remove",*args)) {
    if (thinking || pondering) return(2);
    move_number--;
    sprintf(buffer,"reset %d",move_number);
    (void) Option(tree);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "reset" restores (backs up) a game to a prior position |
|   with the same side on move.  reset 17 would reset the  |
|   position to what it was at move 17.                    |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("reset",*args)) {
    int i, move, nmoves;

    if (thinking || pondering) return(2);
    if (nargs < 2) {
      printf("usage:  reset <movenumber>\n");
      return(1);
    }
    ponder_move=0;
    last_mate_score=0;
    last_pv.path_iteration_depth=0;
    last_pv.path_length=0;
    if (thinking || pondering) return(2);
    over=0;
    move_number=atoi(args[1]);
    if (!move_number) {
      move_number=1;
      return(1);
    }
    nmoves=(move_number-1)*2+1-wtm;
    root_wtm=ChangeSide(wtm);
    InitializeChessBoard(&tree->position[0]);
    wtm=1;
    move_number=1;
    for (i=0;i<nmoves;i++) {
      fseek(history_file,i*10,SEEK_SET);
      fscanf(history_file,"%s",buffer);
/*
    If the move is "pass", that means that the side on move passed.
    This includes the case where the game started from a black-to-move
    position; then white's first move is recorded as a pass.
*/
      if(strcmp(buffer,"pass")==0) {
	wtm=ChangeSide(wtm);
	if (wtm) move_number++;
	continue;
      }
      move=InputMove(tree,buffer,0,wtm,0,0);
      if (move) {
        MakeMoveRoot(tree,move,wtm);
      }
      else {
        printf("ERROR!  move %s is illegal\n",buffer);
        break;
      }
      wtm=ChangeSide(wtm);
      if (wtm) move_number++;
      Phase();
    } 
    moves_out_of_book=0;
    tc_moves_remaining=tc_moves-move_number+1;
    while (tc_moves_remaining <= 0) tc_moves_remaining+=tc_secondary_moves;
    printf("NOTICE: %d moves to next time control\n",tc_moves_remaining);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "read" reads game moves in and makes them.  this can   |
|   be used in two ways:  (1) type "read" and then start   |
|   entering moves;  type "exit" when done;  (2) type      |
|   "read <filename>" to read moves in from <filename>.    |
|   note that read will attempt to skip over "non-move"    |
|   text and try to extract moves if it can.               |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("read",*args) || OptionMatch("reada",*args)) {
    int append, move, readstat;
    FILE *read_input=0;

    if (thinking || pondering) return(2);
    nargs=ReadParse(buffer,args," 	=");
    if (!strcmp("reada",*args))
      append=1;
    else
      append=0;
    ponder_move=0;
    last_pv.path_iteration_depth=0;
    last_pv.path_length=0;
    if (nargs > 1) {
      if (!(read_input=fopen(args[1],"r"))) {
        printf("file %s does not exist.\n",args[1]);
        return(1);
      }
    }
    else {
      printf("type \"exit\" to terminate.\n");
      read_input=stdin;
    }
    if (!append) {
      InitializeChessBoard(&tree->position[0]);
      wtm=1;
      move_number=1;
    }
/*
   step 1:  read in the PGN tags.
*/
    readstat=ReadPGN(0,0);
    do {
      if (read_input == stdin) {
        if (wtm)
          printf("read.White(%d): ",move_number);
        else
          printf("read.Black(%d): ",move_number);
        fflush(stdout);
      }
      readstat=ReadPGN(read_input,0);
    } while (readstat==1);
    if (readstat < 0) return(1);
/*
   step 2:  read in the moves.
*/
    do {
      move=0;
      move=ReadNextMove(tree,buffer,0,wtm);
      if (move) {
        if (read_input != stdin) {
          printf("%s ",OutputMove(tree,move,0,wtm));
          if (!(move_number % 8) && ChangeSide(wtm)) printf("\n");
        }
        fseek(history_file,((move_number-1)*2+1-wtm)*10,SEEK_SET);
        fprintf(history_file,"%9s\n",OutputMove(tree,move,0,wtm));
        MakeMoveRoot(tree,move,wtm);
#if defined(DEBUG)
        ValidatePosition(tree,1,move,"Option()");
#endif
      }
      else if (!read_input) printf("illegal move.\n");
      if (move) {
        wtm=ChangeSide(wtm);
        Phase();
        if (wtm) move_number++;
      }
      if (read_input == stdin) {
        if (wtm)
          printf("read.White(%d): ",move_number);
        else
          printf("read.Black(%d): ",move_number);
        fflush(stdout);
      }
      readstat=ReadPGN(read_input,0);
      if (readstat < 0) break;
      if (!strcmp(buffer,"exit")) break;
    } while (1);
    moves_out_of_book=0;
    if (read_input != stdin) {
      printf("\n");
      fclose(read_input);
    }
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "resign" command sets the resignation threshold to     |
|   the number of pawns the program must be behind before  |
|   resigning (0 -> disable resignations).  resign with no |
|   arguments will mark the pgn result as lost by the      |
|   opponent.                                              |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("resign",*args)) {
    if (nargs < 2) {
      if (crafty_is_white) {
        Print(4095,"result 1-0\n");
        strcpy(pgn_result,"1-0");
      }
      else {
        Print(4095,"result 0-1\n");
        strcpy(pgn_result,"0-1");
      }
      return(1);
    }
    resign=atoi(args[1]);
    if (resign)
      Print(128,"threshold set to %d pawns.\n",resign);
    else
      Print(128,"disabled resignations.\n");
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "result" command comes from xboard/winboard and gives  |
|   the result of the current game.  if learning routines  |
|   have not yet been activated, this will do it.          |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("result",*args)) {
    if (nargs > 1) {
      if (!strcmp(args[1],"1-0")) {
        strcpy(pgn_result,"1-0");
        if (!crafty_is_white) LearnResult(tree,crafty_is_white);
      }
      else if (!strcmp(args[1],"0-1")) {
        strcpy(pgn_result,"0-1");
        if (crafty_is_white) LearnResult(tree,crafty_is_white);
      }
      else if (!strcmp(args[1],"1/2-1/2")) {
        strcpy(pgn_result,"1/2-1/2");
      }
      return(1);
    }
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "savegame" command saves the game in a file in PGN     |
|   format.  command has an optional filename.  note that  |
|   SR is an auto232alias that behaves slightly            |
|   differently.                                           |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("savegame",*args) ||
           OptionMatch("SR",*args)) {
    struct tm *timestruct;
    int i, secs, more, swtm;
    FILE *output_file;
    char input[128], text[128], *next, *tomove;

    output_file=stdout;
    secs=time(0);
    timestruct=localtime((time_t*) &secs);
    if (nargs > 1) {
      if (!(output_file=fopen(args[1],"w"))) {
        printf("unable to open %s for write.\n",args[1]);
        return(1);
      }
    }
    fprintf(output_file,"[Event \"%s\"]\n",pgn_event);
    fprintf(output_file,"[Site \"%s\"]\n",pgn_site);
    fprintf(output_file,"[Date \"%4d.%02d.%02d\"]\n",timestruct->tm_year+1900,
            timestruct->tm_mon+1,timestruct->tm_mday);
    fprintf(output_file,"[Round \"%s\"]\n",pgn_round);
    fprintf(output_file,"[White \"%s\"]\n",pgn_white);
    fprintf(output_file,"[WhiteElo \"%s\"]\n",pgn_white_elo);
    fprintf(output_file,"[Black \"%s\"]\n",pgn_black);
    fprintf(output_file,"[BlackElo \"%s\"]\n",pgn_black_elo);
    fprintf(output_file,"[Result \"%s\"]\n",pgn_result);
    /* Handle setup positions and initial pass by white */
    swtm=1;
    if (move_number>1 || !wtm) {
      fseek(history_file,0,SEEK_SET);
      if (fscanf(history_file,"%s",input)==1 && strcmp(input,"pass")==0) {
	swtm=0;
      }
    }
    if (initial_position[0]) {
      tomove=strchr(initial_position,' ');
      tomove[1]=(swtm?'w':'b');
      fprintf(output_file,"[FEN \"%s\"]\n[SetUp \"1\"]\n",initial_position);
    } else if (!swtm) {
      fprintf(output_file,
        "[FEN \"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR b KQkq - 0 1\"\n"
	"[SetUp \"1\"]\n");
    }
    fprintf(output_file,"\n");
    next=text;
    if (!swtm) {
      strcpy(next,"1... ");
      next=text+strlen(text);
    }
/* Output the moves */
    more=0;
    for (i=(swtm?0:1);i<(move_number-1)*2-wtm+1;i++) {
      fseek(history_file,i*10,SEEK_SET);
      fscanf(history_file,"%s",input);
      if (!(i%2)) {
        sprintf(next,"%d. ",i/2+1);
        next=text+strlen(text);
      }
      sprintf(next,"%s ",input);
      next=text+strlen(text);
      more=1;
      if (next-text >= 60) {
        fprintf(output_file,"%s\n",text);
        more=0;
        next=text;
      }
    }
    if (more)
      fprintf(output_file,"%s",text);
    fprintf(output_file,"%s\n",pgn_result);
    if (output_file != stdout) fclose(output_file);
    printf("PGN save complete.\n");
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "savepos" command saves the current position in a FEN  |
|   (Forsythe notation) string that can be later used to   |
|   recreate this exact position.                          |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("savepos",*args)) {
    char xlate[15]={'q','r','b',0,'k','n','p',0,'P','N','K',0,'B','R','Q'};
    char empty[9]={' ','1','2','3','4','5','6','7','8'};
    int rank, file, nempty;
    FILE *output_file;
  
    output_file=stdout;
    if (nargs > 1) {
      if (!strcmp(args[1],"*")) {
        output_file=0;
        strcpy(initial_position,"");
      }
      else if (!(output_file=fopen(args[1],"w"))) {
        printf("unable to open %s for write.\n",args[1]);
        return(1);
      }
    }
    if (output_file) fprintf(output_file,"setboard ");
    for (rank=RANK8;rank>=RANK1;rank--) {
      nempty=0;
      for (file=FILEA;file<=FILEH;file++) {
        if (PieceOnSquare((rank<<3)+file)) {
          if (nempty) {
            if (output_file)
              fprintf(output_file,"%c",empty[nempty]);
            else
              sprintf(initial_position+strlen(initial_position),"%c",
                      empty[nempty]);
            nempty=0;
          }
          if (output_file)
            fprintf(output_file,"%c",xlate[PieceOnSquare((rank<<3)+file)+7]);
            else
              sprintf(initial_position+strlen(initial_position),"%c",
                      xlate[PieceOnSquare((rank<<3)+file)+7]);
        }
        else nempty++;
      }
      if (output_file)
        fprintf(output_file,"/");
      else
        sprintf(initial_position+strlen(initial_position),"%c",'/');
    }
    if (output_file)
      fprintf(output_file," %c ",(wtm)?'w':'b');
    else
      sprintf(initial_position+strlen(initial_position)," %c ", (wtm)?'w':'b');
    if (WhiteCastle(0) & 1) {
      if (output_file)
        fprintf(output_file,"K");
      else
        sprintf(initial_position+strlen(initial_position),"%c",'K');
    }
    if (WhiteCastle(0) & 2) {
      if (output_file)
        fprintf(output_file,"Q");
      else
        sprintf(initial_position+strlen(initial_position),"%c",'Q');
    }
    if (BlackCastle(0) & 1) {
      if (output_file)
        fprintf(output_file,"k");
      else
        sprintf(initial_position+strlen(initial_position),"%c",'k');
    }
    if (BlackCastle(0) & 2) {
      if (output_file)
        fprintf(output_file,"q");
      else
        sprintf(initial_position+strlen(initial_position),"%c",'q');
    }
    if (EnPassant(0)) {
      if (output_file)
        fprintf(output_file," %c%c",File(EnPassant(0))+'a',
                              Rank(EnPassant(0))+'1');
      else
        sprintf(initial_position+strlen(initial_position), "%c%c",
                File(EnPassant(0))+'a',
                Rank(EnPassant(0))+'1');
    }
    if (output_file) fprintf(output_file,"\n");
 
    if (output_file && output_file != stdout) {
      fprintf(output_file,"exit\n");
      fclose(output_file);
    }
    if (output_file) printf("FEN save complete.\n");
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "search" command sets a specific move for the search   |
|   to analyze, ignoring all others completely.            |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("search",*args)) {
    if (thinking || pondering) return(2);
    if (nargs < 2) {
      printf("usage:  search <move>\n");
      return(1);
    }
    search_move=InputMove(tree,args[1],0,wtm,0,0);
    if (!search_move) search_move=InputMove(tree,args[1],0,ChangeSide(wtm),0,0);
    if (!search_move) printf("illegal move.\n");
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "settc" command is used to reset the time controls     |
|   after a complete restart.                              |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("settc",*args)) {
    if (thinking || pondering) return(2);
    if (nargs < 4) {
      printf("usage:  settc <moves> <ctime> <otime>\n");
      return(1);
    }
    tc_moves_remaining=atoi(args[1]);
    tc_time_remaining=ParseTime(args[2])*6000;
    tc_time_remaining_opponent=ParseTime(args[3])*6000;
    Print(4095,"time remaining: %s (crafty).\n",
            DisplayTime(tc_time_remaining));
    Print(4095,"time remaining: %s (opponent).\n",
            DisplayTime(tc_time_remaining_opponent));
    Print(4095,"%d moves to next time control (Crafty)\n",
          tc_moves_remaining);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "setboard" command sets the board to a specific        |
|   position for analysis by the program.                  |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("setboard",*args)) {
    if (thinking || pondering) return(2);
    nargs=ReadParse(buffer,args," 	;=");
    SetBoard(nargs-1,args+1,0);
    move_number=1;
    if (!wtm) {
      wtm=1;
      Pass();
    }
    ponder_move=0;
    last_pv.path_iteration_depth=0;
    last_pv.path_length=0;
    over=0;
    strcpy(buffer,"savepos *");
    (void) Option(tree);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "score" command displays static evaluation of the      |
|   current board position.                                |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("score",*args)) {
    int s1, s2=0, s3=0, s4=0, s5=0, s6;

    if (thinking || pondering) return(2);
    root_wtm=ChangeSide(wtm);
    tree->position[1]=tree->position[0];
    PreEvaluate(tree,wtm);
    s6=Evaluate(tree,1,1,-99999,99999);
    s1=Material;
    if (opening) s2=EvaluateDevelopment(tree,1);
    if (TotalWhitePawns+TotalBlackPawns) {
      tree->all_pawns=Or(WhitePawns,BlackPawns);
      s3=EvaluatePawns(tree);
      s4=EvaluatePassedPawns(tree);
      s5=EvaluatePassedPawnRaces(tree,wtm);
    }
    Print(128,"note: scores are for the white side\n");
    Print(128,"material evaluation.................%s\n",
      DisplayEvaluation(s1));
    Print(128,"development.........................%s\n",
      DisplayEvaluation(s2));
    Print(128,"pawn evaluation.....................%s\n",
      DisplayEvaluation(s3));
    Print(128,"passed pawn evaluation..............%s\n",
      DisplayEvaluation(s4));
    Print(128,"passed pawn race evaluation.........%s\n",
      DisplayEvaluation(s5));
    Print(128,"interactive piece evaluation........%s\n",
      DisplayEvaluation(s6-s1-s2-s3-s4-s5));
    Print(128,"total evaluation....................%s\n",
      DisplayEvaluation(s6));
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "sd" command sets a specific search depth to control   |
|   the tree search depth.                                 |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("sd",*args)) {
    if (nargs < 2) {
      printf("usage:  sd <depth>\n");
      return(1);
    }
    search_depth=atoi(args[1]);
    Print(4095,"search depth set to %d.\n",search_depth);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "show" command enables/disables various display        |
|   such as "show extensions" which adds a character to    |
|   each pv move showing if/why it was extended.           |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("show",*args)) {
    if (nargs < 2) {
      printf("usage:  show book\n");
      return(1);
    }
    if (OptionMatch("book",args[1])) {
      show_book=!show_book;
      if (show_book) Print(4095,"show book statistics\n");
      else Print(4095,"don't show book statistics\n");
    }
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "SP" command does nothing, except force main() to      |
|   start a search.  [auto232 compatibility]               |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("SP",*args)) {
    if (thinking) return(2);
    return(-1);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "st" command sets a specific search time to control    |
|   the tree search time.                                  |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("st",*args)) {
    int fract;
    if (nargs < 2) {
      printf("usage:  st <time>\n");
      return(1);
    }
    search_time_limit=atoi(args[1])*100;
    if (strchr(args[1],'.')) {
      fract=atoi(strchr(args[1],'.')+1);
      if (fract<10 && *(strchr(args[1],'.')+1) != '0') fract*=10;
      search_time_limit+=fract;
    }
    Print(4095,"search time set to %.2f.\n",(float)search_time_limit/100.0);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "surplus" command sets a specific time surplus target  |
|   for normal tournament games.                           |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("surplus",*args)) {
    if (nargs == 2) tc_safety_margin=atoi(args[1])*6000;
    Print(4095,"time surplus set to %s.\n",DisplayTime(tc_safety_margin));
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "test" command runs a test suite of problems and       |
|   prints results.                                        |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("test",*args)) {
    nargs=ReadParse(buffer,args,"	 ;=");
    if (thinking || pondering) return(2);
    if (nargs < 2) {
      printf("usage:  test <filename> [exitcnt]\n");
      return(1);
    }
    if (nargs > 2) early_exit=atoi(args[2]);
    Test(args[1]);
    ponder_move=0;
    last_pv.path_iteration_depth=0;
    last_pv.path_length=0;
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "time" controls whether the program uses cpu time or   |
|   wall-clock time for timing.  for tournament play,      |
|   it is safer to use wall-clock timing, for testing it   |
|   may be more consistent to use cpu timing if the        |
|   machine is used for other things concurrently with the |
|   tests being run.                                       |
|                                                          |
|   "time" is also used to set the basic search timing     |
|   controls.  the general form of the command is as       |
|   follows:                                               |
|                                                          |
|     time nmoves/ntime/[nmoves/ntime]/[increment]         |
|                                                          |
|   nmoves/ntime represents a traditional first time       |
|   control when nmoves is an integer representing the     |
|   number of moves and ntime is the total time allowed    |
|   for these moves.  the [optional] nmoves/ntime is a     |
|   traditional secondary time control.  increment is a    |
|   feature related to ics play and emulates the fischer   |
|   clock where "increment" is added to the time left      |
|   after each move is made.                               |
|                                                          |
|   as an alternative, nmoves can be "sd" which represents |
|   a "sudden death" time control of the remainder of the  |
|   game played in ntime.  the optional secondary time     |
|   control can be a sudden-death time control, as in the  |
|   following example:                                     |
|                                                          |
|     time 60/30/sd/30                                     |
|                                                          |
|   this sets 60 moves in 30 minutes, then game in 30      |
|   additional minutes.  an increment can be added if      |
|   desired.                                               |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("time",*args)) {
    if (ics || xboard) {
      tc_time_remaining=atoi(args[1]);
      if (log_file && time_limit>99)
        fprintf(log_file,"time remaining: %s (crafty).\n",
                DisplayTime(tc_time_remaining));
    }
    else {
      if (thinking || pondering) return(2);
      if (nargs == 2) {
        if (!strcmp("cpu",args[1])) {
          time_type=cpu;
          Print(4095,"using cpu time\n");
        }
        else if (!strcmp("elapsed",args[1])) {
          time_type=elapsed;
          Print(4095,"using elapsed time\n");
        }
        else printf("usage:  time cpu|elapsed|<controls>\n");
      }
      else {
        tc_moves=60;
        tc_time=180000;
        tc_moves_remaining=60;
        tc_time_remaining=180000;
        tc_time_remaining_opponent=180000;
        tc_secondary_moves=60;
        tc_secondary_time=180000;
        tc_increment=0;
        tc_sudden_death=0;
/*
  first let's pick off the basic time control (moves/minutes)
*/
        if (nargs > 1)
          if (!strcmp(args[1],"sd")) {
            tc_sudden_death=1;
            tc_moves=1000;
          }
        if (nargs > 2) {
          tc_moves=atoi(args[1]);
          tc_time=atoi(args[2])*100;
        }
/*
  now let's pick off the secondary time control (moves/minutes)
*/
        tc_secondary_time=tc_time;
        tc_secondary_moves=tc_moves;
        if (nargs > 3)
          if (!strcmp(args[3],"sd")) {
            tc_sudden_death=2;
            tc_secondary_moves=1000;
          }
        if (nargs > 4) {
          tc_secondary_moves=atoi(args[3]);
          tc_secondary_time=atoi(args[4])*100;
        }
        if (nargs > 5)
          tc_increment=atoi(args[5])*100;
        tc_time_remaining=tc_time;
        tc_time_remaining_opponent=tc_time;
        tc_moves_remaining=tc_moves;
        if (!tc_sudden_death) {
          Print(4095,"%d moves/%d minutes primary time control\n",
                tc_moves, tc_time/100);
          Print(4095,"%d moves/%d minutes secondary time control\n",
                tc_secondary_moves, tc_secondary_time/100);
          if (tc_increment) Print(4095,"increment %d seconds.\n",tc_increment/100);
        }
        else if (tc_sudden_death == 1) {
          Print(4095," game/%d minutes primary time control\n",
                tc_time/100);
          if (tc_increment) Print(4095,"increment %d seconds.\n",tc_increment/100);
        }
        else if (tc_sudden_death == 2) {
          Print(4095,"%d moves/%d minutes primary time control\n",
                tc_moves, tc_time/100);
          Print(4095,"game/%d minutes secondary time control\n",
                tc_secondary_time/100);
          if (tc_increment) Print(4095,"increment %d seconds.\n",tc_increment/100);
        }
        tc_time*=60;
        tc_time_remaining*=60;
        tc_time_remaining_opponent*=60;
        tc_secondary_time*=60;
        tc_safety_margin=tc_time/6;
      }
    }
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "timeleft" command comes from the custom ICS interface |
|   and indicates how much time is left for white and for  |
|   black.                                                 |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("timeleft",*args)) {
    if (nargs < 3) {
      printf("usage:  timeleft <wtime> <btime>\n");
      return(1);
    }
    if (crafty_is_white) {
      tc_time_remaining=atoi(args[1]);
      tc_time_remaining_opponent=atoi(args[2]);
    }
    else {
      tc_time_remaining_opponent=atoi(args[1]);
      tc_time_remaining=atoi(args[2]);
    }
    if (log_file) {
      fprintf(log_file,"time remaining: %s (crafty).\n",
                       DisplayTime(tc_time_remaining));
      fprintf(log_file,"time remaining: %s (opponent).\n",
                       DisplayTime(tc_time_remaining_opponent));
    }
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "trace" command sets the search trace level which will |
|   dump the tree as it is searched.                       |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("trace",*args)) {
#if defined(FAST)
    printf("Sorry, but I can't display traces when compiled with -DFAST\n");
#else
    if (nargs < 2) {
      printf("usage:  trace <depth>\n");
      return(1);
    }
    trace_level=atoi(args[1]);
    printf("trace=%d\n",trace_level);
#endif
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "tt" command is used to test time control logic.       |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("tt",*args)) {
    int time_used;
    do {
      TimeSet(think);
      printf("time used? ");
      fflush(stdout);
      fgets(buffer,128,stdin);
      if (strlen(buffer)) time_used=atoi(buffer);
      else time_used=time_limit;
      TimeAdjust(time_used,opponent);
      TimeAdjust(time_used,crafty);
      sprintf(buffer,"clock");
      Option(tree);
      move_number++;
    } while (time_used >= 0);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "undo" command backs up 1/2 move, which leaves the     |
|   opposite side on move. [xboard compatibility]          |
|                                                          |
 ----------------------------------------------------------
*/
  else if (!strcmp("undo",*args)) {
    if (thinking || pondering) return(2);
    wtm=ChangeSide(wtm);
    if (ChangeSide(wtm)) move_number--;
    sprintf(buffer,"reset %d",move_number);
    (void) Option(tree);
  }
/*
 ---------------------------------------------------------------
|                                                               |
|   "usage" command controls the time usage multiple factors    |
|  used in the game  - percntage increase or decrease in time   |
|  used up front.  Enter a number between 1 to 100 for the      |
|  % decrease to increase - although other time limitations     !
| controls may kick in.  negatives work as well, may be used    |
| in crafty.rc                                                  |
|                                                               |
 ---------------------------------------------------------------
*/
 else if (OptionMatch("usage",*args)) {
    if (nargs < 2) {
      printf("usage:  usage <percentage>\n");
      return(1);
    }
    usage_level=atoi(args[1]);
    if (usage_level > 50) usage_level=50;
    else if (usage_level < -50) usage_level=-50;
    Print(4095,"time usage up front set to %d percent increase/(-)decrease.\n",
          usage_level);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "whisper" command sets whisper mode for ICS.  =1 will  |
|   whisper mate announcements, =2 will whisper scores and |
|   other info, =3 will whisper scores and PV, =4 adds the |
|   list of book moves, =5 displays the PV after each      |
|   iteration completes, and =6 displays the PV each time  |
|   it changes in an iteration.                            |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("whisper",*args)) {
    if (nargs < 2) {
      printf("usage:  whisper <level>\n");
      return(1);
    }
    whisper=atoi(args[1]);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "wild" command sets up an ICS wild position (only 7 at |
|   present, but any can be added easily, except for those |
|   that Crafty simply can't play (two kings, invisible    |
|   pieces, etc.)                                          |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("wild",*args)) {
    int i;

    if (nargs < 2) {
      printf("usage:  wild <value>\n");
      return(1);
    }
    i=atoi(args[1]);
    switch (i) {
    case 7:
      strcpy(buffer,"setboard 4k/5ppp/////PPP/3K/ w");
      (void) Option(tree);
      break;
    default:
      printf("sorry, only wild7 implemented at present\n");
      break;
    }
  }
/*
 ----------------------------------------------------------
|                                                          |
|   "white" command sets white to move (wtm).              |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("white",*args)) {
    if (thinking || pondering) return(2);
    ponder_move=0;
    last_pv.path_iteration_depth=0;
    last_pv.path_length=0;
    if (!wtm) Pass();
    force=0;
  }
/*
 ----------------------------------------------------------
|                                                          |
|  "xboard" command is normally invoked from main() via    |
|  the xboard command-line option.  it sets proper         |
|  defaults for ics/Xboard interface requirements.         |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("xboard",*args) || OptionMatch("winboard",*args)) {
    if (!xboard) {
      signal(SIGINT,SIG_IGN);
      xboard=1;
      display_options&=4095-1-2-4-8-16-32-128;
      ansi=0;
      printf("\n");
      printf("kibitz Hello from Crafty v%s! (%d cpus)\n",version,CPUS);
      printf("tellics set 1 Crafty v%s (%d cpus)\n",version,CPUS);
      fflush(stdout);
    }
  }
/*
 ----------------------------------------------------------
|                                                          |
|  "?" command does nothing, but since this is the "move   |
|  now" keystroke, if crafty is not searching, this will   |
|  simply "wave it off" rather than produce an error.      |
|                                                          |
 ----------------------------------------------------------
*/
  else if (OptionMatch("?",*args)) {
  }
/*
 ----------------------------------------------------------
|                                                          |
|   unknown command, it must be a move.                    |
|                                                          |
 ----------------------------------------------------------
*/
  else
    return(0);
/*
 ----------------------------------------------------------
|                                                          |
|   command executed, return for another.                  |
|                                                          |
 ----------------------------------------------------------
*/
    return(1);
}

/*
********************************************************************************
*                                                                              *
*   OptionMatch() is used to recognize user commands.  it requires that the    *
*   command (text input which is the *2nd parameter* conform to the following  *
*   simple rules:                                                              *
*                                                                              *
*     1.  the input must match the command, starting at the left-most          *
*         character.                                                           *
*     2.  if the command starts with a sequence of characters that could       *
*         be interpreted as a chess move as well (re for reset and/or rook     *
*         to the e-file) then the input must match enough of the command       *
*         to get past the ambiguity (res would be minimum we will accept       *
*         for the reset command.)                                              *
*                                                                              *
********************************************************************************
*/
int OptionMatch(char *command, char *input)
{
/*
 ----------------------------------------------------------
|                                                          |
|   check for the obvious exact match first.               |
|                                                          |
 ----------------------------------------------------------
*/
  if (!strcmp(command,input)) return(1);
/*
 ----------------------------------------------------------
|                                                          |
|   now use strstr() to see if "input" is in "command."    |
|   the first requirement is that input matches command    |
|   starting at the very left-most character;              |
|                                                          |
 ----------------------------------------------------------
*/
  if (strstr(command,input) == command) return(1);
  return(0);
}

void OptionPerft(TREE *tree, int ply,int depth,int wtm)
{
  int i, *mv;

  tree->last[ply]=GenerateCaptures(tree, ply, wtm, tree->last[ply-1]);
  tree->last[ply]=GenerateNonCaptures(tree, ply, wtm, tree->last[ply]);
  for (mv=tree->last[ply-1];mv<tree->last[ply];mv++) {
    MakeMove(tree,ply,*mv,wtm);
    if (!Check(wtm)) {
      if (ply <= trace_level) {
        for (i=1;i<ply;i++) printf("  ");
        printf("%s\n", OutputMove(tree,*mv,ply,wtm));
      }
      total_moves++;
      if (depth-1) OptionPerft(tree,ply+1,depth-1,ChangeSide(wtm));
    }
    UnMakeMove(tree,ply,*mv,wtm);
  }
}
